7

I need to use java xpath to return by id an xml element as a string.

given...

<svg>
    <g id="Background">
    </g>
    <g id="Outline">
        <polygon fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round"     stroke-miterlimit="10" points=" 119.813,57.875 119.188,57.87" />
    </g>
    <g id="Base_Colour" transform="matrix(0.25 0 0 0.25 0 0)">
        <path fill="#ADB1AF" d="M112.25,208l-8,20.25l-0.5-1.75l0.75-0.5v-1.5l0.75-0.5v-1.5L106,222v-1.5l0.75-0.5v-1.5l0.75-0.5v-1.5"/>
        <path fill="#625595" d="M112.25,208l5.25-14.5l30-30.25l2.25-1.5l41.5-20.5l49.75-9.5h4.25l49,3l48.75"/>
    </g>
</svg>

the value returned needs to be...

<g id="Outline">
    <polygon fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round"     stroke-miterlimit="10" points=" 119.813,57.875 119.188,57.87" />
</g> 

I have googled extensively and nothing I have tried has been able to return the whole element. Xpath is desired because I want to query g tags at any level by id.

2

5 Answers 5

10

The solution I found was to get the org.w3c.dom.Node with xpath (DOM would work too). Then I created a javax.xml.transform.dom.DOMSource from the node and transformed that to a string with javax.xml.transform.TransformerFactory.

Node node = // the node you want to serialize
xmlOutput = new StreamResult(new StringWriter());
transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.transform(new DOMSource(node), xmlOutput);
String nodeAsAString = xmlOutput.getWriter().toString();

This is easily factored into a class for reuse. Unfortunately, the is no .OuterXml property in Java as there is in .NET. All you .NETer's can smirk now.

Sign up to request clarification or add additional context in comments.

Comments

1

No xpath will return a string containing XML syntax, ever.

6 Comments

Figures based on what I have encountered. Do you have an idea of another solution that would fill the requirements above?
Use an xpath to find the element you care about, and then serialize it using the usual Java API to serialize XML to a string.
"No xpath ever"? That's quite seriously worded, There are implementations, in which you can write /*/g[@id='Outline']/outer-xml(.)
@bmargulies, Dont' ever say "never" :) w3.org/TR/xpath-functions-30/#func-serialize
@BeniBela, There is even a standard XPath 3.0 function for this: w3.org/TR/xpath-functions-30/#func-serialize :)
|
0

I solved my problem with this code:

public static String getOuterXml(Node node)
    throws TransformerConfigurationException, TransformerException {
    Transformer transformer = TransformerFactory.newInstance().newTransformer();
    transformer.setOutputProperty("omit-xml-declaration", "yes");

    StringWriter writer = new StringWriter();
    transformer.transform(new DOMSource(node), new StreamResult(writer));
    return writer.toString();         
}

Credits to: chick.Net

Comments

0

Sometime you have to do it without an xml document in Java; and I find below code very use full

import java.io.IOException;
import java.io.StringReader;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

String responseMsg = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><YourMessage><MyTag>MyTagValue</MyTag></YourMessage>";
String expressionToExract = "/YourMessage/MyTag";
String xmlNodeWithData = xpathTester.getXmlNode(responseMsg, expressionToExract);
//above xmlNodeWithData will have this value '<MyTag>MyTagValue</MyTag>'

private String getXmlNode(String resultMsg, String expression)
        throws ParserConfigurationException, SAXException, IOException, XPathExpressionException {
    String xmlNodeWithData="";
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = factory.newDocumentBuilder();
    InputSource is = null;
    StringReader sr = null;
    sr = new StringReader(resultMsg);
    is = new InputSource(sr);

    Document doc = builder.parse(is);
    XPathFactory xPathfactory = XPathFactory.newInstance();
    XPath xpath = xPathfactory.newXPath();
    XPathExpression expr = xpath.compile(expression);

    Node node = (Node)expr.evaluate(doc, XPathConstants.NODE);      
    xmlNodeWithData += "<" + node.getNodeName() + ">";
    NodeList nodeList = node.getChildNodes();

    for (int nodeIndex=0; nodeIndex < nodeList.getLength(); nodeIndex++) {
        Node nodeChild = nodeList.item(nodeIndex);          
        if (nodeChild.getNodeName().contains("#text")) {
            xmlNodeWithData += nodeChild.getTextContent();
            continue;
        }
        xmlNodeWithData += "<" + nodeChild.getNodeName() + ">";         
        xmlNodeWithData += nodeChild.getTextContent();
        xmlNodeWithData += "</" + nodeChild.getNodeName() + ">";
    }
    xmlNodeWithData += "</" + node.getNodeName() + ">";
    if (sr != null) {
        sr.close();
    }
    return xmlNodeWithData;
}

Comments

-1

I don't know about Java, but in the .NET world one will use:

doc.DocumentElement.SelectSingleNode("/*/g[@id='Outline']").OuterXml

4 Comments

the question clearly said "java", why even mentioning .Net here
@lidermin, Yes, and the question clearly said "XPath". The question, besides "java" is clearly tagged with "xml" and "xpath". This answer is for the XPath/XML side of the question -- covers two of the three areas indicated by the tags. And the author explicitly says: "Xpath is desired ". One may know Java but without knowledge of XPath any answer would be substantially incomplete. In case you understand this, reversing your downvote would be appreciated.
@Dimitre_Novatchev, Ok, but no need to down vote my answer below just because of an observation, even more given that the solution I provided is not even mine, I posted the credits there and it will be a copy/paste for any other folk with a similar situation in the Java world
@lidermin, Why do you think that I downvoted your answer? Could you ask the same question to yourself and especially why my answer was downvoted at the same time your comment appeared? I think that your answer may have been downvoted, because it suggests a pure Java solution and this doesn't satisfy the OP's requirement, quote: "Xpath is desired". I hope that the people who downvoted your answer and my answer can now reverse their actions.

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.