Search code examples
javaxmlxpathsubtree

Java XPath API - get string representing subtree


My question is not about xpath syntax, it's related to the java API surrounding xpath. Consider the following xml:

<wrapper>
    <metadata>
        <somefield>somevalue</somefield>
        <anotherfield>othervalue</anotherfield>
    </metadata>
    <data>
        <some>
            <unique>
                <xml>
                    <structure>stuff</structure>
                </xml>
            </unique>
        </some>
    </data>
</wrapper>

I can easily get the metadata fields using xpath by using the following code:

 XPath xp = XPathFactory.newInstance().newXPath();
 Node node = (Node) xp.evaluate("/wrapper/metadata/somefield", xmlDoc, XPathConstants.NODE);
 String somefield = node.getFirstChild().getNodeValue();

I am struggling with how I can get a string representing the subtree of xml starting with the <some> tag. In other words, what code do I write to get a String that when printed out, would print out the following? The xpath query would be "/wrapper/data/some", but I do not know how to utilize the xpath api appropriately.

<some>
    <unique>
        <xml>
            <structure>stuff</structure>
        </xml>
    </unique>
</some>

Solution

  • You simply need to transform the Node you get back from the XPathExpression to a String using a Transformer as you would if you were writing the document to a file, here is a full example:

    public static void main(String[] args) throws Exception {
        final String xml = "<wrapper>\n"
                + "    <metadata>\n"
                + "        <somefield>somevalue</somefield>\n"
                + "        <anotherfield>othervalue</anotherfield>\n"
                + "    </metadata>\n"
                + "    <data>\n"
                + "        <some>\n"
                + "            <unique>\n"
                + "                <xml>\n"
                + "                    <structure>stuff</structure>\n"
                + "                </xml>\n"
                + "            </unique>\n"
                + "        </some>\n"
                + "    </data>\n"
                + "</wrapper>";
        final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new ByteArrayInputStream(xml.getBytes(Charsets.UTF_8)));
        final XPathExpression xpath = XPathFactory.newInstance().newXPath().compile("//some");
        final Node node = (Node) xpath.evaluate(doc, XPathConstants.NODE);
        StringWriter sw = new StringWriter();
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer transformer = tf.newTransformer();
        transformer.setOutputProperty(OutputKeys.METHOD, "xml");
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
        transformer.transform(new DOMSource(node), new StreamResult(sw));
        System.out.println(sw.toString());
    }