0

How can I differentiate between these two pieces of XML with XPath in Java?

<iq type="result">
    <query xmlns="jabber:iq:roster">
    </query>
</iq>

and

<iq type="result">
    <query xmlns="vcard-temp">
    </query>
</iq>

I tried this and it always prints null,

public class Test {

    public static void main(String[] args) throws Exception {
        final String xml = "<iq type=\"result\"><query xmlns=\"jabber:iq:roster\"></query></iq>";

        DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document document = builder.parse(createInputSource(xml));

        XPath xpath = XPathFactory.newInstance().newXPath();
        xpath.setNamespaceContext(new NamespaceContext() {
            @Override
            public String getNamespaceURI(String prefix) {
                switch (prefix) {
                    case "roster":
                        return "jabber:iq:roster";
                    case "vcard":
                        return "vcard-temp";
                }

                return XMLConstants.NULL_NS_URI;
            }

            @Override
            public String getPrefix(String namespaceURI) {
                throw new UnsupportedOperationException("Not supported yet.");
            }

            @Override
            public Iterator getPrefixes(String namespaceURI) {
                throw new UnsupportedOperationException("Not supported yet.");
            }
        });

        Node match = (Node) xpath.evaluate("/iq/roster:query", document, XPathConstants.NODE);
        System.out.println(match);
    }

    private static InputSource createInputSource(String xml) {
        return new InputSource(new StringReader(xml));
    }
}
Chandra Sekar
  • 10,683
  • 3
  • 39
  • 54

1 Answers1

2

Whatever API you're using to query your XML documents with XPath most likely has a way to register namespace prefixes for namespaces, such as with a NamespaceContext.
So you would assign a different prefix to each namespace and retrieve the corresponding nodes with something like:

/iq/jRoster:query
/iq/vcard:query

The other option is to skip the NamespaceContext and use namespace-uri():

/iq/*[local-name() = "query" and namespace-uri() = "jabber:iq:roster"]
/iq/*[local-name() = "query" and namespace-uri() = "vcard-temp"]

It looks like you also need to use setNamespaceAware(true) on the when creating the document builder:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Community
  • 1
  • 1
JLRishe
  • 99,490
  • 19
  • 131
  • 169