这开始让我真的很糟糕。我有这个XML代码:
使用正确的命名空间更新
<?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 :(得分: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 :(得分:7)
我只弃了$ 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()
答案来忽略命名空间,或使用jasso的技术指定movielabs ACNS并按预期使用它。
答案 2 :(得分:1)
将此用于任何命名空间:
var_dump($newXML->xpath("//*:ID"));
答案 3 :(得分:0)
我不熟悉PHP的XML API,但我怀疑问题出在名称空间中。根据xpath方法的工作方式,它可能会搜索具有空命名空间的ID元素。您的ID元素从根元素继承其命名空间。
答案 4 :(得分:0)
您在文档元素(xmlns="http://www.movielabs.com/ACNS"
属性)中定义了一个xml命名空间。名称空间是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]
);
提示:默认命名空间仅用于元素,属性在“无/空命名空间”中,除非它们有前缀。