Skip to content

Commit

Permalink
Processed review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
Willem Otten committed Oct 20, 2024
1 parent 790246f commit 0f41dfb
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,40 +27,31 @@
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;
import org.w3c.dom.Node;
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.
Expand All @@ -83,13 +74,17 @@ 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) {
throw new ModelPreprocessorException(
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) {
Expand All @@ -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<ModelNodeRemoval> modelModelNodeRemovals, ArrayList<NamespaceConfig> namespaces)
private static Document performModelNodeRemovals(Document modelDoc, SaxonXMLUtils xmlHelper,
ArrayList<ModelNodeRemoval> 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);
Expand All @@ -173,24 +150,15 @@ private static Document performModelNodeRemovals(Document modelDoc,
return modelDoc;
}

private static Document performModelAttributeInjections(Document modelDoc,
ArrayList<ModelAttributeInjection> modelAttributeInjections, ArrayList<NamespaceConfig> namespaces)
private static Document performModelAttributeInjections(Document modelDoc, SaxonXMLUtils xmlHelper,
ArrayList<ModelAttributeInjection> 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++) {
Expand All @@ -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()));
Expand All @@ -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<ModelAttributeInjectionValueMapping> foundValueMappings = mai.getValueMappings()
.getModelAttributeInjectionValueMappings().stream()
Expand Down Expand Up @@ -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<NamespaceConfig> namespaces;

public ModelNamespaceContext (ArrayList<NamespaceConfig> 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<String> getPrefixes(String namespaceURI) {
// TODO Auto-generated method stub
return null;
}

}
}

}
103 changes: 103 additions & 0 deletions XGenerate/src/main/java/com/xbreeze/xgenerate/utils/SaxonXMLUtils.java
Original file line number Diff line number Diff line change
@@ -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<NamespaceConfig> 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<NamespaceConfig> namespaces;

public ModelNamespaceContext (ArrayList<NamespaceConfig> 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<String> getPrefixes(String namespaceURI) {
// TODO Auto-generated method stub
return null;
}

}
}

0 comments on commit 0f41dfb

Please sign in to comment.