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
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.
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.
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.
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 );
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With