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)');

<slash>这可能是我在尝试从 RSS 提要中检索元素值时得到一个空字符串的原因吗?

4

4 回答 4

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

据我了解,它们的作用类似于文档定义,并且需要识别某些 XML 元素。

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


,那个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 模式实例表示)。在命名空间 URI 标识的位置提供适当的命名空间文档是一种很好的做法,但这不是必需的(实际上 xhtml 命名空间 URI 指向相关的 W3C 文档,但您正在寻找的 RSS 扩展并不) .

但是请注意,resolveExternalsvalidateOnParse都可能影响目标 xml 引用的 DTD 或模式定义的下载,但不会影响命名空间文档。任何解析器都不会下载这样的文档,因为它是供人类使用的。

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

这可能是我在尝试从 RSS 提要中检索元素值时得到一个空字符串的原因吗?

不。
首先,检查源 xml 是否包含正确的 xmlns 声明,并且它是否包含第三个atom 条目<slash:comments>内的节点(注意,第三个,因为xpath 索引是基于一个的,所以这意味着每个条目都是它自己的第一个条目父节点,第二个等等)。 如果是这样,我怀疑您忘记注册atom命名空间。 尝试这样的事情(改编自用户对DOMXPath::registerNamespace文档的贡献)://atom:entry[1]//atom:entry[2]

$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,您也需要注册默认命名空间。

于 2013-04-03T16:16:12.463 回答
2

你有多个问题。我将尝试一一解决:

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

据我了解,它们的作用类似于文档定义,并且需要识别某些 XML 元素。

是的,只要您有一个带有命名空间的 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。这就是IdentifierLocator的区别。

URI Pill:可以是 URL 或 URN

要使 XML 名称空间正常工作,不需要定位任何内容。只需要标识命名空间。因此,一个有效的 XML 命名空间可以用任何 URI 表示。例如,fantasy:space是一个有效的 URI,并且完全符合指定 XML 命名空间的要求。但是当您在浏览器中输入它时,您甚至不会得到任何服务器响应(您的浏览器不知道“幻想”代表什么)。

因此,您得到的 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,因此无法具体说明为什么它 - 正如我所假设的那样 - 不包含节点。看到来源应该很容易澄清这一点。

在那之前,我只能猜测您可能正在解析一个不包含<atom:entry>元素而只包含元素的 RSS 2 提要<item>。看我的例子:

$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 博客的提要。我已将此作为交互式示例放到网上,因此您可以看到它的实际效果并输入您的提要 URL

顺便说一句:如果您在加载 XMLDOMXPath创建对象,则无需注册命名空间 URI,只要您知道文档中使用了哪些前缀即可。这就是为什么在示例中我没有注册任何命名空间 URI。

于 2013-04-07T13:39:29.430 回答
1

有关名称空间的教程,已有 13 年历史但仍然有用,请参阅

http://www.jclark.com/xml/xmlns.htm

于 2012-11-04T09:33:08.237 回答
1

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

$dom - new DOMDocument($url);
$slashEls = $dom->getElementsbyTagNameNS('slash', 'slash'); // Assuming the element is <slash:slash> in the XML
foreach($slashEls as $slash) {
    // ...
}
于 2012-11-04T00:52:18.707 回答