DOMDocument命名空间有什么作用?

5
$xpath->registerNamespace('slash', 'http://purl.org/rss/1.0/modules/slash/');

据我所知,它们就像文档定义一样,需要用来识别特定的XML元素。

PHP是否实际向该URL发出请求并验证文档定义中是否存在该元素?

因为该URL显示了一个404未找到页面 :(

$result = $xpath->evaluate('string(//atom:entry[3]/slash:comments)');

为什么我从RSS源中尝试检索<slash>元素的值时会得到空字符串,这可能是原因吗?

4个回答

5
$xpath->registerNamespace('slash', 'http://purl.org/rss/1.0/modules/slash/');

From what I understand they act like document definitions, and are required to identify certain XML elements.

Does PHP actually do a request to that URL and verify if the element exists in the document definition?

编号。
URI标识了一个XML命名空间,代表了一种XML词汇。这些命名空间旨在处理在不同上下文中使用具有不同含义的相同术语的情况。使用命名空间,单个XML文件可以包含具有相同“名称”的标记和属性,这些标记和属性通过前缀进行限定。例如,您可以拥有如下的xml文档:

<html xmlns="http://www.w3.org/1999/xhtml" 
        xmlns:human="http://sample.xml.com/Human">
  <title>John Smith measures.</title>
  <body>
    <human:name>John</human:name> <human:surname>Smith</human:surname>
    is <human:height unit="feet">6</human:height> feet tall.
  </body>
</html>

在这种内容中,“human”前缀用于标记来自http://sample.xml.com/Human命名空间的元素,而空字符串(即默认前缀)用于标记来自http://www.w3.org/1999/xhtml命名空间的元素。这些URI是命名空间标识符,而不是模式位置(可以使用DOCTYPE声明XML Schema实例来表示)。在由命名空间URI标识的位置提供命名空间的适当文档是一个好习惯,但不是必需的(实际上,xhtml命名空间URI指向相关的W3C文档,但你正在寻找的RSS扩展并没有)。
请注意,resolveExternalsvalidateOnParse都会影响目标xml引用的DTD或模式定义的下载,但不会影响命名空间文档。绝不会有任何解析器下载此类文档,因为它是供人类使用的。
$result = $xpath->evaluate('string(//atom:entry[3]/slash:comments)');

Could this be the reason why I get an empty string, while trying to retrieve the value of the element from a RSS feed?

编号
首先,检查源XML是否包含正确的xmlns声明,并且在第三个Atom条目内包含一个<slash:comments>节点(注意,第三个是因为XPath索引从1开始,所以//atom:entry[1]表示每个在其父节点中是第一个的条目,//atom:entry[2]表示第二个,依此类推)。
如果是这样,我怀疑你忘记注册atom命名空间了。
尝试像这样做(从用户对DOMXPath::registerNamespace文档的贡献中改编):

$doc = new DOMDocument;
$doc->loadXML($xml); // your xml string here
$xpath = new DOMXPath($doc);

$xpath->registerNamespace('atom', "http://www.w3.org/2005/Atom");
$xpath->registerNamespace('slash', 'http://purl.org/rss/1.0/modules/slash/');

$result =  $xpath->evaluate('string(//atom:entry[3]/slash:comments)');

你可以在http://codepad.org/JX8RpaKu上运行此代码。
实际上,要使用限定的xpath,也需要注册默认命名空间。

2
你有多个问题。我会尝试逐一回答它们:
$xpath->registerNamespace('slash', 'http://purl.org/rss/1.0/modules/slash/');

From what I understand they act like document definitions, and are required to identify certain XML elements.

是的,每当您有一个带有命名空间的XML文档时,那么每个元素都可以在自己的命名空间中。
如果您想要访问它们自己的命名空间中的元素,则确实需要使用该命名空间来标识它们。例如,在XPath表达式中。
在PHP中,DOMDocument和其他基于libxml的XML扩展支持XML命名空间。
PHP实际上会请求该URL并验证该元素是否存在于文档定义中吗?
不,对于您提供的代码示例:
$xpath->registerNamespace('slash', 'http://purl.org/rss/1.0/modules/slash/');

PHP不会请求那个URL。你已经注意到这个URL是空的/返回404,所以你可能想要了解这一切是关于什么的。实际上,那个URL是一个URI。这就是标识符和定位器之间的区别。

The URI Pill: Can be URL or URN

要使XML命名空间起作用,无需定位任何内容。只需要识别命名空间即可。因此,任何URI都可以表示有效的XML命名空间。例如,fantasy:space是一个有效的URI,并且完全符合指定XML命名空间的要求。但是,当您在浏览器中输入它时,您甚至不会收到任何服务器响应(您的浏览器不知道"fantasy"代表什么)。
因此,您获得的404错误不是导致您的XPath评估中斜杠为空的原因:
$result = $xpath->evaluate('string(//atom:entry[3]/slash:comments)');

你之所以在这里得到一个空字符串的原因是不同的。请看XPath表达式:
string(//atom:entry[3]/slash:comments)

这是要求节点集的字符串值。您已将节点集指定为:
//atom:entry[3]/slash:comments

在PHP DOMDocument中,“获取节点集的字符串”意味着:将节点集转换为字符串,方法是返回节点集中按文档顺序排列的第一个节点的节点字符串值。如果节点集为空,则返回空字符串。
由于节点是元素,因此元素节点的字符串值意味着:元素节点的字符串值是元素节点所有文本节点后代的字符串值按文档顺序连接起来的结果。
因此,这里有两种情况会导致你得到一个空字符串:要么节点集为空,要么元素的字符串值正好是一个空字符串。
您可以通过使用count()函数快速了解节点集合中节点的数量:
$result = $xpath->evaluate('count(//atom:entry[3]/slash:comments)');

这段文字的意思是:
“这样,你应该可以更好地了解到哪种情况是真实的。由于你没有分享源XML,不能确定具体的原因,但我猜测它可能不包含节点。查看源文件应该很容易澄清这个问题。”
“在此之前,我只能猜测你可能正在解析一个不包含元素而只有元素的RSS 2.0订阅。请参考我的示例:”
$feed = 'http://hakre.wordpress.com/feed/';

$doc = new DOMDocument();
$doc->load($feed);
$xpath = new DOMXPath($doc);

echo $xpath->evaluate('string(//item[3]/slash:comments)'); # 1

它输出了值“1”作为第三项的评论计数。这是标准WordPress博客的源。我已将其在线发布为交互式示例,因此您可以看到它的运行情况并输入您的Feed URL
顺便说一下:如果在加载XML之后创建DOMXPath对象,则只需知道文档中使用了哪些前缀,就不需要注册命名空间URI。这就是为什么在示例中我没有注册任何命名空间URI的原因。

1

如果您想检索命名空间节点的内容,您尝试过 getElementsByTagNameNS 吗?

$dom - new DOMDocument($url);
$slashEls = $dom->getElementsbyTagNameNS('slash', 'slash'); // Assuming the element is <slash:slash> in the XML
foreach($slashEls as $slash) {
    // ...
}

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接