Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XPath filtering on attribute with namespace

Tags:

php

xml

xslt

xpath

I need to create XPath expression to filter based on attribute that is in given namespace. Example XML is:

<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

like image 546
wurdalack Avatar asked Aug 04 '11 17:08

wurdalack


People also ask

What is namespace in XPath?

XPath queries are aware of namespaces in an XML document and can use namespace prefixes to qualify element and attribute names. Qualifying element and attribute names with a namespace prefix limits the nodes returned by an XPath query to only those nodes that belong to a specific namespace.

What is the meaning of '/' in XPath?

Single Slash “/” – Single slash is used to create Xpath with absolute path i.e. the xpath would be created to start selection from the document node/start node.

What is XML namespace with example?

An XML namespace is a collection of names that can be used as element or attribute names in an XML document. The namespace qualifies element names uniquely on the Web in order to avoid conflicts between elements with the same name.


2 Answers

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.

like image 83
Mads Hansen Avatar answered Sep 25 '22 04:09

Mads Hansen


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 );
like image 23
Kenney Avatar answered Sep 28 '22 04:09

Kenney