DOMDocument 命名空间有啥用?
Posted
技术标签:
【中文标题】DOMDocument 命名空间有啥用?【英文标题】:What are DOMDocument namespaces for?DOMDocument 命名空间有什么用? 【发布时间】:2012-10-24 06:30:24 【问题描述】:$xpath->registerNamespace('slash', 'http://purl.org/rss/1.0/modules/slash/');
据我了解,它们的作用类似于文档定义,并且需要识别某些 XML 元素。
php 是否真的向该 URL 发出请求并验证该元素是否存在于文档定义中?
因为那个 URL 显示了一个404 not found 页面:(
$result = $xpath->evaluate('string(//atom:entry[3]/slash:comments)');
这可能是我在尝试从 RSS 提要中检索 <slash>
元素的值时得到一个空字符串的原因吗?
【问题讨论】:
【参考方案1】:$xpath->registerNamespace('slash', 'http://purl.org/rss/1.0/modules/slash/');
据我了解,它们的作用类似于文档定义,并且需要识别某些 XML 元素。
PHP 是否真的向该 URL 发出请求并验证该元素是否存在于文档定义中?
没有。URI 标识了一个 XML namespace,它表示一个 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 declaration 或 XML Schema instance 表示)。在命名空间 URI 标识的位置提供适当的命名空间文档是一种很好的做法,但这不是必需的(实际上 xhtml 命名空间 URI 指向相关的 W3C 文档,但您正在寻找的 RSS 扩展并不) .
但请注意,resolveExternals
和 validateOnParse
都会影响目标 xml 引用的 DTD 或架构定义的下载,但不会 命名空间文档。任何解析器都不会下载这样的文档,因为它是供人类使用的。
$result = $xpath->evaluate('string(//atom:entry[3]/slash:comments)');
这可能是我在尝试从 RSS 提要中检索元素值时得到一个空字符串的原因吗?
没有。
首先,检查源 xml 是否包含正确的 xmlns 声明,并且它在 third 原子条目内包含 <slash:comments>
节点(注意,第三个,因为 xpath 索引是基于一个的,因此//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/');
据我了解,它们的作用类似于文档定义,并且需要识别某些 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。这就是 Identifier 和 Locator 的区别。
要使 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
Getting a string of a nodeset 在 PHP DOMDocument 中的意思是:
通过在文档顺序中的第一个节点集中返回string-value of the node,将节点集转换为字符串。如果节点集为空,则返回一个空字符串。
由于节点是一个元素,所以the element node的string-value表示:
元素节点的字符串值是该元素节点的所有文本节点后代的字符串值按文档顺序串联。
所以这里有两个解释为什么你得到一个空字符串:节点集是空的或者元素字符串值只是一个空字符串。
您可以使用count()
function 快速了解节点集中的节点数量:
$result = $xpath->evaluate('count(//atom:entry[3]/slash:comments)');
那么这应该让您更好地了解这两种情况中的哪一种。由于您没有共享源 XML,因此无法具体说明 why 但是它 - 正如我所假设的那样 - 不包含节点。看到来源应该很容易澄清这一点。
在那之前,我只能猜测您可能正在解析一个不包含 <atom:entry>
元素而只包含 <item>
元素的 RSS 2 提要。看我的例子:
$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 博客的提要。 I have put this online as an interactive example, so you can see it in action and enter your feed URL.
顺便说一句:如果您在加载 XML 之后创建 DOMXPath
对象,则无需注册命名空间 URI,只要您知道在文档。这就是为什么在示例中我没有注册任何命名空间 URI。
【讨论】:
【参考方案3】:如果您想检索命名空间节点的内容,您是否尝试过getElementsByTagNameNS?
$dom - new DOMDocument($url);
$slashEls = $dom->getElementsbyTagNameNS('slash', 'slash'); // Assuming the element is <slash:slash> in the XML
foreach($slashEls as $slash)
// ...
【讨论】:
【参考方案4】:有关命名空间的教程,已有 13 年历史但仍然有用,请参阅
http://www.jclark.com/xml/xmlns.htm
【讨论】:
以上是关于DOMDocument 命名空间有啥用?的主要内容,如果未能解决你的问题,请参考以下文章
带有 PhpWord 的隐蔽 HTML:错误 - DOMDocument::loadXML(): 实体中未定义 p 上的命名空间前缀 o