Reputation: 27266
Say I have the following XML file:
<A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:foo="http://foo"
xsi:type="foo:SomeSubtypeOfA">
boo
</A>
I wish to require that the XML instance is of a specific type derived from A
, e.g. type {http://foo}SomeSubtypeOfA
(as indeed the above example is). So I am using the following XPath:
/*[@xsi:type='foo:SomeSubtypeOfA']
... and check whether it succeeds in returning a node or not. However the XPath above is problematic as it relies on the arbitrary prefix so it fails on the following file:
<A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:foo2="http://foo"
xsi:type="foo2:SomeSubtypeOfA">
boo
</A>
... and it produces a false match on the following file:
<A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:foo="http://fooX"
xsi:type="foo:SomeSubtypeOfA">
boo
</A>
To get rid of the false match I could write the XPath as:
/*[namespace::foo[.='http://foo'] and @xsi:type='foo:SomeSubtypeOfA']
But that still fails to account for the possibility of some other prefix bound to the http://foo
namespace. How can I write the above XPath so it checks the namespace of the type given in the xsi:type
attribute rather than its prefix?
Upvotes: 2
Views: 786
Reputation: 163262
In XPath 2.0 you can do
/*[namespace-uri-from-QName(resolve-QName(@xsi:type, .)) = 'http://foo' and local-name-from-QName(resolve-QName(@xsi:type, .)) = 'SomeSubtypeOfA']
In XPath 1.0 you need to do something like
//*[namespace::*[name()=substring-before(../@xsi:type, ':')] = 'http://foo/']
(but that probably doesn't allow for the type being in the default namespace)
Upvotes: 3