2010-09-15 149 views
3

这开始让我感到非常不好。我有这样的XML代码:xPath找不到任何东西,但*

用正确的命名空间

<?xml version="1.0" encoding="utf-8"?> 

<Infringement xsi:schemaLocation="http://www.movielabs.com/ACNS http://www.movielabs.com/ACNS/ACNS2v1.xsd" xmlns="http://www.movielabs.com/ACNS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <Case> 
    <ID>...</ID> 
    <Status>Open</Status> 
    </Case> 
    <Complainant> 
    <Entity>...</Entity> 
    <Contact>...</Contact> 
    <Address>...</Address> 
    <Phone>...</Phone> 
    <Email>...</Email> 
    </Complainant> 
    <Service_Provider> 
    <Entity>...</Entity> 
    <Address></Address> 
    <Email>...</Email> 
    </Service_Provider> 
    <Source> 
    <TimeStamp>...</TimeStamp> 
    <IP_Address>...</IP_Address> 
    <Port>...</Port> 
    <DNS_Name></DNS_Name> 
    <Type>...</Type> 
    <UserName></UserName> 
    <Number_Files>1</Number_Files> 
    <Deja_Vu>No</Deja_Vu> 
    </Source> 
    <Content> 
    <Item> 
     <TimeStamp>...</TimeStamp> 
     <Title>...</Title> 
     <FileName>...</FileName> 
     <FileSize>...</FileSize> 
     <URL></URL> 
    </Item> 
    </Content> 
</Infringement> 

更新,此PHP代码:

<?php 
    $data = urldecode($_POST["xml"]); 
    $newXML = simplexml_load_string($data); 

    var_dump($newXML->xpath("//ID")); 
?> 

我甩了只$ newXML,并得到吨的数据,但只有xPath我运行,返回任何东西,但空数组是“*”

是不是“ID”应该找到文档中的所有ID节点?为什么它不工作?

感谢

+0

问题很可能是命名空间('xmlns:xsi')。不知道如何进一步帮助,但不足的技能':P' – Kobi 2010-09-15 16:19:00

+0

不确定,但尝试用'ns'替换'xmlns'。 (受[此PHP.net上的此评论]启发(http://nl2.php.net/manual/en/simplexmlelement.xpath.php#96153)。 – Lekensteyn 2010-09-15 16:26:48

+3

我可能听起来像一个狂热但恕我直言删除命名空间,使XPath查询的工作仅仅是用来克服任何的编程工具的缺陷或程序员的无能XML打破黑客。命名空间是XML中的一个基本概念。任何想使用XML的人都应该学会理解它们。 – jasso 2010-09-15 16:43:54

回答

6

我甩了只$ newXML并得到 吨的数据,但唯一的XPath我 传回任何东西,但一个 空数组运行是“*”

那又是什么从var_dump($newXML->xpath("*"));返回? <Infringement>

如果问题是命名空间,试试这个:

var_dump($newXML->xpath("//*[local-name() = 'ID']")); 

这将他的名字是“ID”文档中的任何元素匹配,无论命名空间。

我的东西的作品,如果我全部更换 “的xmlns” 与 “NS”

等等,什么?您确定您向我们展示了文档中所有与xmlns相关的属性吗?

更新: 该问题被编辑,以表明XML确实有一个默认的命名空间声明。这解释了原始问题:由于默认的名称空间声明,XPath表达式选择了没有名称空间的ID元素,但文档中的元素位于movielabs ACNS名称空间中。

元素上的声明xmlns="http://www.movielabs.com/ACNS"意味着“此元素和所有没有名称空间前缀(如ID)的后代位于名称空间URI'http://www.movielabs.com/ACNS'所表示的名称空间中”。 (除非介入的后代有不同的默认命名空间声明,这将阴影在这一个。)

所以用我上面的local-name()答案忽略的命名空间,或者使用学生支援机构的技术来指定movielabs ACNS,并以此为意。

+0

'local-name()'然后。我的脚本将会得到大量的XML文档,并且我不能确定它们都具有相同的默认命名空间 – Hubro 2010-09-15 17:03:17

+0

@Codemonkey,这是一个很好的解决方案。如果你不知道它们的默认命名空间,但它们都在同一个命名空间中(可能使用命名空间前缀),你仍然可以使用jasso的方法,因为脚本中的前缀不必与XML文档。只有名称空间URI必须匹配。或者你可以完全忽略名称空间。 – LarsH 2010-09-15 17:25:10

0

我不是很精通PHP的XML API,但我怀疑问题出在命名空间。根据xpath方法的工作原理,它可能会搜索具有空名称空间的ID元素。您的ID元素从根元素继承其名称空间。

+0

我甚至没有稍微理解 - 对不起 – Hubro 2010-09-15 16:20:02

+0

我误读了它还是曾经在侵权元素上使用过xmlns属性? – Simon 2010-09-15 16:21:56

+0

有,是的。其中两个。如果我用“ns”替换所有的“xmlns”,但我的东西能够正常工作,但是没有办法改变* XML? – Hubro 2010-09-15 16:26:46

8

您的XML文档的根元素似乎具有URI为“http://www.movielabs.com/ACNS”的默认名称空间。这意味着文档中的所有元素都属于该名称空间。问题是没有名称空间前缀的所有XPath表达式都在搜索不属于任何名称空间的元素。要从某个名称空间搜索元素(或属性...),您需要将名称空间URI注册为某个前缀,然后在您的XPath表达式中使用此前缀。

在PHP的SimpleXML的情况下,它做了这样的事情

$newXML = simplexml_load_string($data); 
$newXML->registerXPathNamespace('prefix', 'http://www.movielabs.com/ACNS'); 
var_dump($newXML->xpath("//prefix:ID")); 

prefix可以是几乎任何文字,但空间URI必须与您的XML文档中使用的一个相匹配。

1

使用这种用于任何命名空间:

var_dump($newXML->xpath("//*:ID")); 
+0

这适用于XPath 2.0,但不适用于1.0。 – LarsH 2010-09-16 02:37:29

0

你必须在文档元素定义的XML命名空间(该xmlns="http://www.movielabs.com/ACNS"属性)。命名空间是URL http://www.movielabs.com/ACNS。这必须由一个全球唯一的字符串(一个URN)。由于这些URL经常被使用。有人使用你的域名作为命名空间的可能性非常低,你可以在URL处添加一些文档。

XML解析器解析名称空间。该节点获得4个属性。

<Infringement xmlns="http://www.movielabs.com/ACNS"/>

$namespaceURI => http://www.movielabs.com/ACNS 
$localName => Infringement 
$prefix => 
$nodeName => Infringement 

对于<movie:Infringement xmlns:movie="http://www.movielabs.com/ACNS"/>

$namespaceURI => http://www.movielabs.com/ACNS 
$localName => Infringement 
$prefix => movie 
$nodeName => movie:Infringement 

$namespaceURI$localName是稳定的。另外两个取决于前缀。前缀是名称空间的别名。命名空间uri很长且很复杂,如果在每个元素/属性上使用XML,读取和写入会变得更加困难。但是,你能解释像元素节点:

{http://www.movielabs.com/ACNS}:Infringement 

所以命名空间的一两件事,它定义了节点的意思是,没有前缀/别名。前缀可以在子元素上重新定义。

<foo xmlns="urn:foo"><bar xmlns="urn:bar"/></foo> 

Xpath对自己的解析器使用相同的概念。您为一个名称空间注册自己的前缀。因此,在XML中如何使用前缀并不重要,只有名称空间uri必须匹配。

在DOM这样做的DOMXPath实例:

$dom = new DOMDocument(); 
$dom->loadXml($xml); 
$xpath = new DOMXpath($dom); 
$xpath->registerNamespace('movie', 'http://www.movielabs.com/ACNS'); 

var_dump(
    $xpath->evaluate('string(/movie:Infringement/movie:Case/movie:ID)') 
); 

SimpleXML中,你可以注册上的SimpleXMLElement的命名空间。

$element = simplexml_load_string($xml); 
$element->registerXpathNamespace('movie', 'http://www.movielabs.com/ACNS'); 
var_dump(
    (string)$element->xpath('/movie:Infringement/movie:Case/movie:ID')[0] 
); 

提示:默认命名空间仅用于元素,属性是“无/空命名空间”,除非他们有一个前缀。

相关问题