Following is my XML file
<xyzevent xmlns="http://www.xyz.com/common/xyzevent/v1" xmlns:xsi="http://www.w3.org2001XMLSchema-instance">
<header>
----
</header>
<subscription xmlns="http://www.xyz.com/common/xyzevent/source/v1">
<sender></sender>
<receiver>
<clientsubscription>
<servicemap>nanna</servicemap>
</clientsubscription>
</receiver>
</subscription>
</xyzevent>
When I budila org.w3c.dom.Document from this XML and applying XPathExperssion with expression
/xyzevent/subscription/receiver/clientsubscription/servicemap/text()
results empty string. What can be the issue with the expression?
Thank you
That's because your XML document uses a namespace. XPath is really annoying with namespaces. To confirm this, strip the two xmlns=http://.../v1
from the document and run your XPath expression agains the unnamespaced, unverifiable XML file. It'll match.
What's happening is that your XPath expression tries to select /xyzevent
, when your document contains {http://.../v1}:xyzevent
, which is not the same thing.
There are various ways around this problem. The proper way is to set up a NamespaceContext
so you can use the prefix:localName
notation in your XPath expression and have the prefixes be resolved to the correct URI. There's a short blurb about this in the xerces docs and some more elsewhere on StackOverflow. There's an extensive description at ibm.com.
Your NamespaceContext
will contain two (or more) mappings:
{
event => http://www.xyz.com/common/xyzevent/v1
source => http://www.xyz.com/common/xyzevent/source/v1
}
Your XPath expression can then become /event:xyzevent/source:subscription/source:receiver/.../text()
.
As a nasty workaround, you can rewrite your xpath expression to select using the local-name()
function:
/*[local-name()='xyzevent']/*[local-name()='subscription'/ ...
In this case, the expression matches any element whose local name is xyzevent
, regardless of namespace URI.
Your XML has default namespace: xmlns="http://www.xyz.com/common/xyzevent/v1"
, therefore you need to define it in your XML/XPath engine.
Or use this XPath:
/*[local-name() = 'xyzevent']
/*[local-name() = 'subscription']
/*[local-name() = 'receiver']
/*[local-name() = 'clientsubscription']
/*[local-name() = 'servicemap']
/text()
xyzevent
is your root element, so you just need to use "/subscription/receiver/clientsubscription/servicemap/text()"
.
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