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.

jeremyjjbrown
  • 7,772
  • 5
  • 43
  • 55

5 Answers5

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.

jeremyjjbrown
  • 7,772
  • 5
  • 43
  • 55
1

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

bmargulies
  • 97,814
  • 39
  • 186
  • 310
  • Figures based on what I have encountered. Do you have an idea of another solution that would fill the requirements above? – jeremyjjbrown Dec 19 '12 at 01:35
  • 2
    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. – bmargulies Dec 19 '12 at 01:37
  • 2
    "No xpath ever"? That's quite seriously worded, There *are* implementations, in which you can write `/*/g[@id='Outline']/outer-xml(.)` – BeniBela Dec 19 '12 at 22:29
  • That's not in any standard I know of, and honestly it's news to me. If you want to make an answer stating what Java lib supports it I'd cheeerfully upvote. – bmargulies Dec 20 '12 at 01:49
  • 2
    @bmargulies, Dont' ever say "never" :) http://www.w3.org/TR/xpath-functions-30/#func-serialize – Dimitre Novatchev Dec 20 '12 at 02:14
  • 3
    @BeniBela, There is even a *standard* XPath 3.0 function for this: http://www.w3.org/TR/xpath-functions-30/#func-serialize :) – Dimitre Novatchev Dec 20 '12 at 02:15
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

lidermin
  • 2,782
  • 11
  • 43
  • 48
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;
}
Aamir
  • 655
  • 1
  • 8
  • 27
-1

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

doc.DocumentElement.SelectSingleNode("/*/g[@id='Outline']").OuterXml
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
  • 1
    the question clearly said "java", why even mentioning .Net here – lidermin Jun 14 '17 at 18:58
  • @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 Jun 14 '17 at 19:54
  • @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 Jun 28 '17 at 20:25
  • @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. – Dimitre Novatchev Jun 28 '17 at 22:16