带有命名空间的属性的XPath过滤

时间:2011-08-04 17:22:09

标签: php xml xslt xpath

我需要根据给定命名空间中的属性创建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>

我需要获取节点的url,其属性yt:name设置为'hqdefault'。

我尝试使用XPath表达式

'./media:group/media:thumbnail[@yt:name='hqdefault']/@url'

但似乎用yt:name指定namespaced属性不起作用。我在进行查询时得到一个空的DOMNodeList。

我在php中访问XML,所以我注册了yt namespace:

registerNamespace( 'yt', 'http://gdata.youtube.com/schemas/2007' );

Thnx提前

3 个答案:

答案 0 :(得分:5)

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

如果这样可行,则在注册这些名称空间前缀的名称空间时会出现问题。

答案 1 :(得分: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 :(得分:0)

yt名称空间前缀用于示例XML,但未声明。如果那个示例XML确实存在,那么它就不是格式良好的XML(在命名空间术语中)。因此,没有通用的XML工具(如XSLT)可能能够处理它。

另一方面,如果源文档中某处有yt名称空间前缀的声明,但您没有向我们展示过,那么您需要在XPath处理环境中声明(我猜是XSLT)相同名称空间URI的前缀。 E.g。

<xsl:stylesheet ... xmlns:yt="theNamespaceURIForYT">

XPath不知道源文档中出现的任何名称空间前缀声明。它只知道每个元素(和属性)属于哪个命名空间(URI)。