diff --git a/Backend/xslt-rest/src/main/java/com/r11/tools/xslt/processors/Xalan.java b/Backend/xslt-rest/src/main/java/com/r11/tools/xslt/processors/Xalan.java index 42db619..85fb7e7 100644 --- a/Backend/xslt-rest/src/main/java/com/r11/tools/xslt/processors/Xalan.java +++ b/Backend/xslt-rest/src/main/java/com/r11/tools/xslt/processors/Xalan.java @@ -1,8 +1,12 @@ package com.r11.tools.xslt.processors; +import net.sf.saxon.lib.RawResult; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.xpath.XPathAPI; import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.traversal.NodeIterator; import org.xml.sax.InputSource; import javax.xml.XMLConstants; @@ -19,8 +23,7 @@ import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathFactory; -import java.io.StringReader; -import java.io.StringWriter; +import java.io.*; /** * Handler for Xalan engine @@ -53,25 +56,55 @@ public class Xalan { return sw.toString(); } + private static boolean isTextNode(Node n) { + if (n == null) + return false; + short nodeType = n.getNodeType(); + return nodeType == Node.CDATA_SECTION_NODE || nodeType == Node.TEXT_NODE; + } + /** * Process xpath and return either node or wrapped atomic value - * @deprecated - * Xalan needs assumption of the outcome, which is not implemented. Therefore method is deprecated * @param data xml * @param transform xpath * @return xml processed using given xpath * @throws Exception thrown on node building errors or invalid xpath */ - public static String processXPath(String data, String transform) throws Exception{ - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = factory.newDocumentBuilder(); + public static String processXPath(String data, String transform) throws Exception { - XPath xpath = XPathFactory.newInstance().newXPath(); + // Set up a DOM tree to query. + InputSource in = new InputSource(new StringReader(data)); + DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); + dfactory.setNamespaceAware(true); + Document doc = dfactory.newDocumentBuilder().parse(in); - xpath.setNamespaceContext(new XalanNamespaceResolver(builder.parse(new InputSource(new StringReader(data))), true)); - XPathExpression exp = xpath.compile(transform); - exp.evaluate(new InputSource(new StringReader(data)), XPathConstants.NODESET); - return exp.evaluate(new InputSource(new StringReader(data))); + // Set up an identity transformer to use as serializer. + Transformer serializer = TransformerFactory.newInstance().newTransformer(); + serializer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); + + // Use the simple XPath API to select a nodeIterator. + NodeIterator nl = XPathAPI.selectNodeIterator(doc, transform); + + // Serialize the found nodes to result object. + StringBuilder result = new StringBuilder(); + Node n; + while ((n = nl.nextNode())!= null) { + StringBuilder sb; + if (isTextNode(n)) { + // DOM may have more than one node corresponding to a + // single XPath text node. Coalesce all contiguous text nodes + // at this level + for (Node nn = n.getNextSibling(); isTextNode(nn); nn = nn.getNextSibling()) { + result.append(nn.getNodeValue()); + } + } else { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + serializer.transform(new DOMSource(n), new StreamResult(new OutputStreamWriter(outputStream))); + result.append(outputStream); + } + result.append("\n"); + } + return result.toString(); } /** diff --git a/Frontend/tools/xpath.html b/Frontend/tools/xpath.html index 1d4a84d..d10a60b 100644 --- a/Frontend/tools/xpath.html +++ b/Frontend/tools/xpath.html @@ -24,6 +24,7 @@