0

I'm using XOM library to parse xmls. I have the following XML

<ns4:parent xmlns:ns4="http://sample.xml.com/ns4">
    <ns4:child1 xmlns:ns1="http://sample.xml.com/ns1" xmlns:xsi="http://sample.xml.com/xsi">
        <ns1:child2>divaStatus</ns1:child2>
        <xsi:child>something</xsi:child>
    </ns4:child1>
</ns4:parent>

And I want to apply a xpath like ns4:parent/ns4:child1/ns1:child2. So my code is like below

Document doc = new Builder().build(inStream);  //inStream is containing the xml
XPathContext xc = XPathContext.makeNamespaceContext(doc.getRootElement());
doc.query("ns4:parent/ns4:child1/ns1:child2", xc);

And I'm getting XPathException here.

 Exception in thread "main" nu.xom.XPathException: XPath error: XPath expression uses unbound namespace prefix ns1.

I can understand that since im making the namespace context by Root Element only, its not getting the namespaces of its children. So one work around might be traversing through all the children and collecting their namespaces and add it into the XpathContext object. But my xml can be of 10 to 20k lines. So Im afraid that how efficient the traversal approach will be.

Looking forward for any better suggestion

Samiron
  • 5,169
  • 2
  • 28
  • 55

2 Answers2

2

This is easy (or as easy as it can be, given the design of XPath and XML Namespaces). You just need to add any namespaces you want to use to the context manually. For instance, in this case,

XPathContext xc = new XPathContext();
xc.addNamespace("ns4", "http://sample.xml.com/ns4");
xc.addNamespace("ns1", "http://sample.xml.com/ns1");
doc.query("ns4:parent/ns4:child1/ns1:child2", xc);

Note that you do not have to use the same prefixes in the XPath expression that the document uses.

  • :) Its nice to get a reply from the direct developer of the library on a problem. Thanks a lot for that. And yes eventually we took this approach to solve this problem. We maintained all probable namespace definitions in a single place and preparing a context with those and using that context to parse the xml. But it will fail if the xml introduces any new namespace. So its kind of "not so dynamic" right now. Do you have any suggestion on this? – Samiron Apr 24 '13 at 09:40
  • I agree about getting Elliotte's feedback. There is also a mailing list [xom-interest@lists.ibiblio.org] but I expect many people come here first and the answers are easier to revisit. – peter.murray.rust Apr 24 '13 at 15:35
0

Presumably you know the namespace which is associated with each element name. So you could write:

String xpath = "*[local-name()='parent' and namespace-uri()='http://sample.xml.com/ns4']"+
  "*[local-name()='child1' and namespace-uri()='http://sample.xml.com/ns2']"+
  "*[local-name()='child2' and namespace-uri()='http://sample.xml.com/ns1']";

I would expect that to be as efficient as the prefixed version.

peter.murray.rust
  • 37,407
  • 44
  • 153
  • 217