diff --git a/XGenerate/src/main/java/com/xbreeze/xgenerate/model/ModelPreprocessor.java b/XGenerate/src/main/java/com/xbreeze/xgenerate/model/ModelPreprocessor.java index dac3aec..9c208a4 100644 --- a/XGenerate/src/main/java/com/xbreeze/xgenerate/model/ModelPreprocessor.java +++ b/XGenerate/src/main/java/com/xbreeze/xgenerate/model/ModelPreprocessor.java @@ -27,27 +27,17 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.logging.Logger; import java.util.stream.Collectors; -import javax.xml.namespace.NamespaceContext; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; -import net.sf.saxon.xpath.XPathFactoryImpl; -import net.sf.saxon.xpath.XPathEvaluator; import net.sf.saxon.xpath.XPathExpressionImpl; - import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Attr; @@ -55,12 +45,13 @@ import org.w3c.dom.NodeList; import org.xml.sax.SAXException; -import com.xbreeze.xgenerate.config.NamespaceConfig; import com.xbreeze.xgenerate.config.model.ModelAttributeInjection; import com.xbreeze.xgenerate.config.model.ModelConfig; import com.xbreeze.xgenerate.config.model.ModelNodeRemoval; import com.xbreeze.xgenerate.config.model.ModelAttributeInjectionValueMapping; -import java.io.StringWriter; +import com.xbreeze.xgenerate.utils.SaxonXMLUtils; +import com.xbreeze.xgenerate.utils.XmlException; + /** * The model preprocessor. @@ -83,6 +74,7 @@ public static void preprocessModel(Model model, ModelConfig modelConfig) throws // Load the preprocessed model into memory DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder; + try { builder = factory.newDocumentBuilder(); } catch (ParserConfigurationException exc) { @@ -90,6 +82,9 @@ public static void preprocessModel(Model model, ModelConfig modelConfig) throws String.format("Error while reading model XML file: %s", exc.getMessage())); } Document doc; + SaxonXMLUtils xmlHelper = new SaxonXMLUtils(); + xmlHelper.setNamespaces(modelConfig.getNamespaces()); + try { doc = builder.parse(new ByteArrayInputStream(model.getModelFileContent().getBytes())); } catch(SAXException | IOException exc) { @@ -103,59 +98,41 @@ public static void preprocessModel(Model model, ModelConfig modelConfig) throws // removed in the next step if (modelConfig != null && modelConfig.getModelAttributeInjections() != null && modelConfig.getModelAttributeInjections().size() > 0) { - doc = performModelAttributeInjections(doc, - modelConfig.getModelAttributeInjections(), modelConfig.getNamespaces()); + doc = performModelAttributeInjections(doc, xmlHelper, + modelConfig.getModelAttributeInjections()); } // ModelNodeRemovals if (modelConfig != null && modelConfig.getModelNodeRemovals() != null && modelConfig.getModelNodeRemovals().size() > 0) { - doc = performModelNodeRemovals(doc, modelConfig.getModelNodeRemovals(), - modelConfig.getNamespaces()); + doc = performModelNodeRemovals(doc, xmlHelper, modelConfig.getModelNodeRemovals()); } //Transform the preprocessed document to string and store it in the model object. - String preprocessedModel = null; - DOMSource domSource = new DOMSource(doc); - StringWriter writer = new StringWriter(); - StreamResult result = new StreamResult(writer); - TransformerFactory tf = TransformerFactory.newInstance(); - Transformer transformer; + String preprocessedModel; try { - transformer = tf.newTransformer(); - transformer.transform(domSource, result); - } catch (TransformerException e) { - throw new ModelPreprocessorException( - String.format("Error transforming model XML document to string: %s", e.getMessage()) - ); + preprocessedModel = SaxonXMLUtils.XmlDocumentToString(doc); + } catch (XmlException e) { + throw new ModelPreprocessorException(String.format("Error transforming preprocessed model to string: %s", e.getMessage())); } - preprocessedModel = writer.toString(); + + // Store the pre-processed model as string in the Model object. model.setPreprocessedModel(preprocessedModel); logger.info("End model preprocessing"); } - private static Document performModelNodeRemovals(Document modelDoc, - ArrayList modelModelNodeRemovals, ArrayList namespaces) + private static Document performModelNodeRemovals(Document modelDoc, SaxonXMLUtils xmlHelper, + ArrayList modelModelNodeRemovals) throws ModelPreprocessorException { logger.fine("Performing model node removals."); - - XPathFactoryImpl xPathfactory = new XPathFactoryImpl(); - XPathEvaluator xpath = (XPathEvaluator) xPathfactory.newXPath(); - // If namespaces are defined, create a namespace context object and set it on the xpath object. - if (namespaces != null && namespaces.size() > 0) { - ModelNamespaceContext nsContext = new ModelNamespaceContext(namespaces); - xpath.setNamespaceContext(nsContext); - } - - // Loop through the model node removals and process them. for (ModelNodeRemoval mnr : modelModelNodeRemovals) { try { - XPathExpressionImpl expr = (XPathExpressionImpl)xpath.compile(mnr.getModelXPath()); + XPathExpressionImpl expr = xmlHelper.getXPathExpression(mnr.getModelXPath()); NodeList result = (NodeList) expr.evaluate(modelDoc, XPathConstants.NODESET); for (int i = 0; i < result.getLength(); i++) { Node node = result.item(i); @@ -173,24 +150,15 @@ private static Document performModelNodeRemovals(Document modelDoc, return modelDoc; } - private static Document performModelAttributeInjections(Document modelDoc, - ArrayList modelAttributeInjections, ArrayList namespaces) + private static Document performModelAttributeInjections(Document modelDoc, SaxonXMLUtils xmlHelper, + ArrayList modelAttributeInjections) throws ModelPreprocessorException { logger.fine("Performing model attribute injections."); - - XPathFactoryImpl xPathfactory = new XPathFactoryImpl(); - XPathEvaluator xpath = (XPathEvaluator) xPathfactory.newXPath(); - - // If namespaces are defined, create a namespace context object and set it on the xpath object. - if (namespaces != null && namespaces.size() > 0) { - ModelNamespaceContext nsContext = new ModelNamespaceContext(namespaces); - xpath.setNamespaceContext(nsContext); - } // Loop through the model attribute injections and process them. for (ModelAttributeInjection mai : modelAttributeInjections) { try { - XPathExpressionImpl expr = (XPathExpressionImpl)xpath.compile(mai.getModelXPath()); + XPathExpressionImpl expr = xmlHelper.getXPathExpression(mai.getModelXPath()); NodeList result = (NodeList) expr.evaluate(modelDoc, XPathConstants.NODESET); for (int i = 0; i < result.getLength(); i++) { @@ -199,7 +167,7 @@ private static Document performModelAttributeInjections(Document modelDoc, //If a target xpath is set, evaluate it to get a value if (mai.getTargetXPath() !=null) { try { - XPathExpressionImpl targetExpression = (XPathExpressionImpl)xpath.compile(mai.getTargetXPath()); + XPathExpressionImpl targetExpression = xmlHelper.getXPathExpression(mai.getTargetXPath()); targetValue = (String)targetExpression.evaluate(node, XPathConstants.STRING); } catch (XPathExpressionException e) { throw new ModelPreprocessorException(String.format("Error while processing model attribute injection for target XPath ´%s´: %s", mai.getTargetXPath(), e.getMessage())); @@ -209,7 +177,7 @@ private static Document performModelAttributeInjections(Document modelDoc, } else if (mai.getValueMappings() != null ) { //Get the input node value to use for finding the mapped output value try { - XPathExpressionImpl valueMappingExpression = (XPathExpressionImpl)xpath.compile(mai.getValueMappings().getInputNode()); + XPathExpressionImpl valueMappingExpression = xmlHelper.getXPathExpression(mai.getValueMappings().getInputNode()); String inputNodeValue = (String)valueMappingExpression.evaluate(node, XPathConstants.STRING); List foundValueMappings = mai.getValueMappings() .getModelAttributeInjectionValueMappings().stream() @@ -249,42 +217,4 @@ else if (foundValueMappings.size() > 1) { // Return the modified XML document. return modelDoc; } - - // helper class to deal with namespace aware preprocessing - private static class ModelNamespaceContext implements NamespaceContext { - - private ArrayList namespaces; - - public ModelNamespaceContext (ArrayList namespaces) { - this.namespaces = namespaces; - } - - @Override - public String getNamespaceURI(String prefix) { - for (NamespaceConfig ns: this.namespaces) { - if (ns.getPrefix().equalsIgnoreCase(prefix)) { - return ns.getNamespace(); - } - } - return null; - } - - @Override - public String getPrefix(String namespaceURI) { - for (NamespaceConfig ns: this.namespaces) { - if (ns.getNamespace().equalsIgnoreCase(namespaceURI)) { - return ns.getPrefix(); - } - } - return null; - } - - @Override - public Iterator getPrefixes(String namespaceURI) { - // TODO Auto-generated method stub - return null; - } - - } -} - +} \ No newline at end of file diff --git a/XGenerate/src/main/java/com/xbreeze/xgenerate/utils/SaxonXMLUtils.java b/XGenerate/src/main/java/com/xbreeze/xgenerate/utils/SaxonXMLUtils.java new file mode 100644 index 0000000..8b8a171 --- /dev/null +++ b/XGenerate/src/main/java/com/xbreeze/xgenerate/utils/SaxonXMLUtils.java @@ -0,0 +1,103 @@ +package com.xbreeze.xgenerate.utils; + +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Iterator; + +import org.w3c.dom.Document; + +import com.xbreeze.xgenerate.config.NamespaceConfig; + +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.namespace.NamespaceContext; + +import net.sf.saxon.xpath.XPathEvaluator; +import net.sf.saxon.xpath.XPathExpressionImpl; +import net.sf.saxon.xpath.XPathFactoryImpl; + +public class SaxonXMLUtils { + + private XPathEvaluator _xpath = null; + + public static String XmlDocumentToString(Document doc) throws XmlException { + //Transform the preprocessed document to string and store it in the model object. + DOMSource domSource = new DOMSource(doc); + StringWriter writer = new StringWriter(); + StreamResult result = new StreamResult(writer); + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer transformer; + try { + transformer = tf.newTransformer(); + transformer.transform(domSource, result); + } catch (TransformerException e) { + throw new XmlException( + String.format("Error transforming document to string: %s", e.getMessage()) + ); + } + return writer.toString(); + } + + //Evaluate the xpath expression and return the result as an XPathExpressionImpl object + public XPathExpressionImpl getXPathExpression(String xPathExpression) throws XPathExpressionException { + return(XPathExpressionImpl)this.getXPathEvaluator().compile(xPathExpression); + } + + //Return the XPathEvaluator, if it is not yet initialized, create a new one + public XPathEvaluator getXPathEvaluator() { + if (this._xpath == null) { + XPathFactoryImpl xPathfactory = new XPathFactoryImpl(); + this._xpath = (XPathEvaluator) xPathfactory.newXPath(); + } + return this._xpath; + } + + public void setNamespaces(ArrayList namespaces) { + // If namespaces are defined, create a namespace context object and set it on the xpath object. + if (namespaces != null && namespaces.size() > 0) { + ModelNamespaceContext nsContext = new ModelNamespaceContext(namespaces); + this.getXPathEvaluator().setNamespaceContext(nsContext); + } + } + + // helper class to deal with namespace aware preprocessing + private static class ModelNamespaceContext implements NamespaceContext { + + private ArrayList namespaces; + + public ModelNamespaceContext (ArrayList namespaces) { + this.namespaces = namespaces; + } + + @Override + public String getNamespaceURI(String prefix) { + for (NamespaceConfig ns: this.namespaces) { + if (ns.getPrefix().equalsIgnoreCase(prefix)) { + return ns.getNamespace(); + } + } + return null; + } + + @Override + public String getPrefix(String namespaceURI) { + for (NamespaceConfig ns: this.namespaces) { + if (ns.getNamespace().equalsIgnoreCase(namespaceURI)) { + return ns.getPrefix(); + } + } + return null; + } + + @Override + public Iterator getPrefixes(String namespaceURI) { + // TODO Auto-generated method stub + return null; + } + + } +}