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.
精彩评论