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 @@