开发者

XPath filtering on attribute with namespace

开发者 https://www.devze.com 2023-03-26 11:38 出处:网络
I need to create XPath expression to filter based on attribute that is in given namespace. Example XML is:开发者_JAVA技巧

I need to create XPath expression to filter based on attribute that is in given namespace. Example XML is:开发者_JAVA技巧

<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>

And I need to get the url of the node with attribute yt:name set to 'hqdefault'.

I tried with XPath expression

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

but it seems that specifying namespaced attribute with yt:name does not work. I get an empty DOMNodeList upon making a query.

I am accessing XML in php, so I registered yt namespace:

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

Thnx in advance


That XPath looks correct.

It could be that your library doesn't support namespaced attributes, or that you haven't properly registered the yt namespace and/or the media namespace.

Try just matching on the local-name() and namespace-uri() inside of predicate filters, rather than using the namespace-prefix:

./*[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

If this works, then there is an issue registering the namespaces for those namespace-prefixes.


Assuming the rest is in order, simply replace the first . in the xpath with / to get //media:group/... (or begin with /atom:feed/media:group/... and register the atom namespace).

Here's a complete working example:

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


The yt namespace prefix is used in your example XML, but is not declared. If that example XML is really all there is, it's not well-formed XML (in namespace terms). Therefore no generic XML tools, such as XSLT, are likely to be able to process it.

On the other hand if there is a declaration of the yt namespace prefix somewhere in your source document that you haven't shown us, then you need to declare in your XPath processing environment (XSLT I guess) a prefix for the same namespace URI. E.g.

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

XPath is not aware of any namespace prefix declarations that occur in the source document. It only knows what namespace (URI) each element (and attribute) belongs to.

0

精彩评论

暂无评论...
验证码 换一张
取 消