1

I have the following xml

<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<abc:root-example xmlns:abc="http://www.example.com/abc">
  <abc:test-object Name="DesiredObject">
    <root xmlns="http://www.example.com">
      <value>Hello world</value>
    </root>
  </abc:test-object>
</abc:root-example>

and the following java code

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(xmlFilePath.toFile());

XPath xpath = XPathFactory.newInstance().newXPath();

xpath.setNamespaceContext(new NamespaceContext() {
    @Override
    public String getNamespaceURI(String s) {
        if (s.equals("abc")) {
            return "http://www.example.com/abc";
        }
        return null;
    }

    @Override
    public String getPrefix(String s) {
        return null;
    }

    @Override
    public Iterator<String> getPrefixes(String s) {
        return null;
    }
});

XPathExpression expr = xpath.compile("//abc:test-object/root");
Node node = (Node) expr.evaluate(doc, XPathConstants.NODE);

The final node here always ends up being null. If I remove xmlns="http://www.example.com" from the root node, then the evaluation returns the expected node. It's unclear to me how I properly format the XPath request to get the node. I believe it has something to do with root using a different default namespace, but am having difficult figuring it out.

3
  • That is the FAQ of XPath 1, use a prefix to qualify the element name e.g. ex:root in XPath and have your API (e.g. getNamespaceURI) return the URI http://www.example.com for that prefix ex. Commented Dec 21, 2022 at 20:38
  • So, in this case, is the XML sample that I posted poorly formed for using XPath? Commented Dec 21, 2022 at 20:54
  • I don't see it that way, the sample is fine, for the selection of the element in a default namespace it doesn't matter anyway what is outside, and for XPath 1 you need a prefix to select/qualify that element in XPath expressions, it's just that most people expect to be able to use root in XPath if the element has that local name, in XPath 2 and later you can do that by declaring a default element namespace but obviously you can have only one so with e.g. <foo xmlns="http://example.com/"><bar xmlns="http://example.org/"/></foo> your XPath needs to use a prefix or wildcard for one of them. Commented Dec 21, 2022 at 21:02

1 Answer 1

1

I've found the following:

  1. In getNamespaceURI(...), the value null is returned if the namespace prefix is not abc. But the default namespace's URI is http://www.example.com instead.

  2. In the XPath query, no namespace prefix given for root. This is reasonable since it should use the default namespace, however it seems necessary to explicitly give an empty prefix now: :root.

Applying both changes will make the code return the node.

xpath.setNamespaceContext(new NamespaceContext() {
    @Override
    public String getNamespaceURI(String s) {
        if (s.equals("abc")) {
            return "http://www.example.com/abc";
        }
        return "http://www.example.com";
    }

    @Override
    public String getPrefix(String s) {
        return null;
    }

    @Override
    public Iterator<String> getPrefixes(String s) {
        return null;
    }
});

XPathExpression expr = xpath.compile("//abc:test-object/:root");
Node node = (Node) expr.evaluate(doc, XPathConstants.NODE);
System.out.println(node == null ? "null" : node);  // just to show

Output:

[root: null]

Update: As Martin Honnen points out, although accepted by javax.xml.xpath, :root is not a valid XPath expression. Also, javax.xml.xpath is only XPath 1.0 compliant. I've found another, rather verbose way to select the node with //abc:test-object/*[local-name()=\"root\"], but it probably makes more sense to either just

  • use namespace prefixes or
  • use an XPath 2.0 compliant library
Sign up to request clarification or add additional context in comments.

1 Comment

If some implementation swallows, fine, as long as you know that implementation, that but with the step :root in//abc:test-object/:root that expression is not even a syntactically correct XPath expression (w3.org/TR/1999/REC-xpath-19991116/#NT-NameTest).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.