使用命名空间对属性进行 XPath 过滤
Posted
技术标签:
【中文标题】使用命名空间对属性进行 XPath 过滤【英文标题】:XPath filtering on attribute with namespace 【发布时间】:2011-10-20 05:19:33 【问题描述】:我需要创建 XPath 表达式以根据给定命名空间中的属性进行过滤。示例 XML 是:
<feed xmlns='http://www.w3.org/2005/Atom' xmlns:media='http://search.yahoo.com/mrss/'
xmlns:yt='http://gdata.youtube.com/schemas/2007'> ...
<entry>
<media:group>
<media:thumbnail url='http://i.ytimg.com/1.jpg' yt:name='default'/>
<media:thumbnail url='http://i.ytimg.com/2.jpg' yt:name='hqdefault'/>
<media:thumbnail url='http://i.ytimg.com/3.jpg' yt:name='start'/>
<media:thumbnail url='http://i.ytimg.com/4.jpg' yt:name='middle'/>
</media:group>
</entry>
我需要获取属性 yt:name 设置为 'hqdefault' 的节点的 url。
我尝试了 XPath 表达式
'./media:group/media:thumbnail[@yt:name='hqdefault']/@url'
但似乎用 yt:name 指定命名空间属性不起作用。进行查询时,我得到一个空的 DOMNodeList。
我在 php 中访问 XML,所以我注册了 yt 命名空间:
registerNamespace( 'yt', 'http://gdata.youtube.com/schemas/2007' );
提前谢谢
【问题讨论】:
“不起作用” - 你需要说出发生了什么。错误信息? 【参考方案1】:假设其余的都按顺序进行,只需将 xpath 中的第一个 .
替换为 /
即可获得 //media:group/...
(或以 /atom:feed/media:group/...
开头并注册 atom 命名空间)。
这是一个完整的工作示例:
<?php
$dom = new DOMDocument();
$dom->loadXML( <<<XML
<feed xmlns='http://www.w3.org/2005/Atom' xmlns:media='http://search.yahoo.com/mrss/'
xmlns:yt='http://gdata.youtube.com/schemas/2007'>
<entry>
<media:group>
<media:thumbnail url='http://i.ytimg.com/1.jpg' yt:name='default'/>
<media:thumbnail url='http://i.ytimg.com/2.jpg' yt:name='hqdefault'/>
<media:thumbnail url='http://i.ytimg.com/3.jpg' yt:name='start'/>
<media:thumbnail url='http://i.ytimg.com/4.jpg' yt:name='middle'/>
</media:group>
</entry>
</feed>
XML
);
$x = new DOMXPath( $dom );
$x->registerNamespace( 'yt', 'http://gdata.youtube.com/schemas/2007' );
$x->registerNamespace( 'media', 'http://search.yahoo.com/mrss/' );
$l= $x->query( "//media:group/media:thumbnail[@yt:name='hqdefault']/@url" );
for ($i=0; $i<$l->length; $i++) var_dump( $l->item($i)->value );
【讨论】:
【参考方案2】:XPath 看起来是正确的。
可能是您的库不支持命名空间属性,或者您没有正确注册 yt
命名空间和/或 media
命名空间。
尝试只匹配谓词过滤器内的local-name()
和namespace-uri()
,而不是使用命名空间前缀:
./*[local-name()='group'
and namespace-uri()='http://search.yahoo.com/mrss/'
]/*[local-name()='thumbnail'
and namespace-uri()='http://search.yahoo.com/mrss/'
and @*[local-name()='name'
and namespace-uri()='http://gdata.youtube.com/schemas/2007'
and .='hqdefault'
]
]/@url
如果可行,那么为这些命名空间前缀注册命名空间时会出现问题。
【讨论】:
【参考方案3】:yt
命名空间前缀在您的示例 XML 中使用,但未声明。如果该示例 XML 确实存在,那么它不是格式良好的 XML(在命名空间方面)。因此,没有通用 XML 工具(例如 XSLT)可能能够处理它。
另一方面,如果在您的源文档中某处声明了 yt
命名空间前缀但您没有向我们展示,那么您需要在您的 XPath 处理环境(我猜是 XSLT)中声明一个前缀相同的命名空间 URI。例如
<xsl:stylesheet ... xmlns:yt="theNamespaceURIForYT">
XPath 不知道源文档中出现的任何名称空间前缀声明。它只知道每个元素(和属性)所属的命名空间(URI)。
【讨论】:
我没有输入整个 XML,抱歉。它是 YouTube 播放列表导出 XML,它以:<feed xmlns='http://www.w3.org/2005/Atom' xmlns:media='http://search.yahoo.com/mrss/' xmlns:openSearch='http://a9.com/-/spec/opensearch/1.1/' xmlns:gd='http://schemas.google.com/g/2005' xmlns:yt='http://gdata.youtube.com/schemas/2007' gd:etag='W/&quot;C04ESH47eCp7ImA9WhZWGUk.&quot;'>
开头,我在 php 中访问 XML,所以我注册了 yt 命名空间:registerNamespace( 'yt', 'http://gdata.youtube.com/schemas/2007' );
在进行查询时我得到一个空的 DOMNodeList 是行不通的。谢谢以上是关于使用命名空间对属性进行 XPath 过滤的主要内容,如果未能解决你的问题,请参考以下文章