|
package transform;
|
|
|
|
|
|
|
|
import net.sf.saxon.lib.StandardLogger;
|
|
import net.sf.saxon.s9api.*;
|
|
|
|
import net.sf.saxon.trace.XSLTTraceListener;
|
|
import net.sf.saxon.trans.XPathException;
|
|
import net.sf.saxon.type.ValidationException;
|
|
|
|
//import org.apache.commons.lang3.StringUtils;
|
|
|
|
|
|
import javax.xml.transform.ErrorListener;
|
|
import javax.xml.transform.SourceLocator;
|
|
import javax.xml.transform.TransformerException;
|
|
import javax.xml.transform.stream.StreamSource;
|
|
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.DataInputStream;
|
|
import java.io.File;
|
|
import java.io.FileInputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.PrintStream;
|
|
import java.io.StringReader;
|
|
import java.io.StringWriter;
|
|
import java.io.UnsupportedEncodingException;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* Model loading scheme XSLT processing engine.
|
|
*/
|
|
class TransformXML {
|
|
|
|
|
|
//private static final ILogger logger = new Logger(ModelLoadingSchemeXsltProcessor.class);
|
|
|
|
private static final String REFERENCE_PRODUCT_PARAM_NAME = "refProdDoc";
|
|
|
|
|
|
private Processor processor;
|
|
private Serializer serializer;
|
|
private XsltCompiler xsltCompiler;
|
|
private XsltExecutable xsltExecutable;
|
|
private XsltTransformer xsltTransformer;
|
|
private DocumentBuilder documentBuilder;
|
|
|
|
|
|
|
|
|
|
private List<String> transformationLog = new ArrayList<>();
|
|
|
|
/**
|
|
* Receiver for XSLT compilation errors and warnings. It is consumed by {@code XsltCompiler}.
|
|
* In the case of error() and warning(), the XSLT processor is required to continue processing
|
|
* the document until the end. For fatalError() the XSLT processor is not required to continue.
|
|
*/
|
|
private class ErrorListenerImpl implements ErrorListener {
|
|
@Override
|
|
public void error(TransformerException exception) throws TransformerException {
|
|
String message = getUserFriendlyMessage(exception);
|
|
if (!transformationLog.contains(message)) {
|
|
transformationLog.add(message);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void fatalError(TransformerException exception) throws TransformerException {
|
|
String message = getUserFriendlyMessage(exception);
|
|
if (!transformationLog.contains(message)) {
|
|
transformationLog.add(message);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void warning(TransformerException exception) throws TransformerException {
|
|
//logger.warning("", exception);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Receiver for custom XSLT debug messages in the form of {@code xsl:message}. It is consumed
|
|
* by @{code XsltTransformer}.
|
|
*/
|
|
private class MessageListenerImpl implements MessageListener {
|
|
@Override
|
|
public void message(XdmNode content, boolean terminate, SourceLocator locator) {
|
|
try {
|
|
String message = locator.getSystemId() + ":L" + locator.getLineNumber() + " : " + content.getTypedValue();
|
|
transformationLog.add(message);
|
|
// logger.info(message);
|
|
} catch (SaxonApiException e) {
|
|
// logger.error("", e);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialize the XSLT processor using the input XSL transformation document
|
|
*
|
|
* @param loadingScheme XSL transformation document
|
|
* @throws SaxonApiException if {@code XsltCompiler} failed to compile the input XSLT document. This exception
|
|
* occurs in case the input string is not a valid XSLT document.
|
|
*/
|
|
TransformXML(String loadingScheme) throws SaxonApiException {
|
|
/* if (StringUtils.isEmpty(loadingScheme)) {
|
|
loadingScheme = DEFAULT_LOADING_SCHEME_XSLT;
|
|
}*/
|
|
final boolean isLicensed = false;
|
|
processor = new Processor(isLicensed);
|
|
xsltCompiler = processor.newXsltCompiler();
|
|
xsltCompiler.setErrorListener(new ErrorListenerImpl());
|
|
xsltExecutable = xsltCompiler.compile(new StreamSource(new StringReader(loadingScheme)));
|
|
|
|
}
|
|
|
|
/**
|
|
* Transform input stream using reference product
|
|
*
|
|
* @param referenceProduct the XSLT input parameter
|
|
* @param inputStream input to transform
|
|
* @return the transformation result
|
|
* @throws IOException if failed to create a string writer
|
|
* @throws SaxonApiException if failed to transform the input stream
|
|
*/
|
|
public String transform(String referenceProduct, InputStream inputStream) throws IOException, SaxonApiException {
|
|
if (xsltTransformer == null) {
|
|
serializer = processor.newSerializer();
|
|
xsltTransformer = xsltExecutable.load();
|
|
xsltTransformer.setDestination(serializer);
|
|
xsltTransformer.setMessageListener(new MessageListenerImpl());
|
|
documentBuilder = processor.newDocumentBuilder();
|
|
XdmNode paramNode = documentBuilder.build(new StreamSource(new StringReader(referenceProduct)));
|
|
xsltTransformer.setParameter(new QName(REFERENCE_PRODUCT_PARAM_NAME), paramNode);
|
|
}
|
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
PrintStream stream = new PrintStream(baos); //("c:\\test\\output.xml");
|
|
StandardLogger theLogger = new StandardLogger(stream);
|
|
XSLTTraceListener traceListener = new XSLTTraceListener();
|
|
traceListener.setOutputDestination(theLogger);
|
|
xsltTransformer.setTraceListener(traceListener);
|
|
|
|
String result;
|
|
XdmNode contextNode = null;
|
|
try (StringWriter stringWriter = new StringWriter()) {
|
|
serializer.setOutputWriter(stringWriter);
|
|
contextNode = documentBuilder.build(new StreamSource(inputStream));
|
|
xsltTransformer.setInitialContextNode(contextNode);
|
|
xsltTransformer.transform();
|
|
String productDefinition = stringWriter.toString();
|
|
|
|
result = productDefinition ;//fillInProductDefinitionIterators(productDefinition);
|
|
|
|
} catch (SaxonApiException e) {
|
|
String message = getUserFriendlyMessage(e);
|
|
|
|
transformationLog.add(0, message);
|
|
throw e;
|
|
}
|
|
finally {
|
|
stream.flush();
|
|
stream.close();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get a list of compilation errors and transformation debug messages of form {@code xsl:message}.
|
|
* Transformation warnings are not returned but are logged using the default system logger instead.
|
|
*
|
|
* @return the list of error and debug messages
|
|
*/
|
|
List<String> getTransformationLog() {
|
|
return transformationLog;
|
|
}
|
|
|
|
/**
|
|
* Fill-in all the product definition iterators with their default values
|
|
*
|
|
* @param productDefinition product definition XML
|
|
* @return the product definition with all the iterators set to their default values
|
|
* @throws IOException if failed to create a string writer
|
|
* @throws SaxonApiException if transformation failed
|
|
*/
|
|
|
|
|
|
/**
|
|
* Remove the exception class from the exception message for user-friendly presentation
|
|
*
|
|
* @param throwable exception to format
|
|
* @return the formatted exception message
|
|
*/
|
|
private String getUserFriendlyMessage(Throwable throwable) {
|
|
String result = throwable.getMessage().replaceFirst("^[\\w.]*;?\\s*", "");
|
|
return result;
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
|
|
try {
|
|
|
|
String referenceProductFileName = args[0];
|
|
byte[] refProdBytes = getBytes(referenceProductFileName);
|
|
String referenceProduct = new String(refProdBytes, "UTF-8");
|
|
|
|
String schemeFileName = args[1];
|
|
byte[] schemeBytes = getBytes(schemeFileName);
|
|
String scheme = new String(schemeBytes, "UTF-8");
|
|
|
|
String sourceXML = args[2];
|
|
byte[] sourceXMLBytes = getBytes(sourceXML);
|
|
ByteArrayInputStream inputStream = new ByteArrayInputStream(sourceXMLBytes);
|
|
|
|
TransformXML transformXML = new TransformXML(scheme);
|
|
transformXML.transform(referenceProduct, inputStream);
|
|
|
|
} catch (Exception e) {
|
|
// TODO Auto-generated catch block
|
|
//e.printStackTrace();
|
|
ByteArrayOutputStream errorBaos = new ByteArrayOutputStream();
|
|
PrintStream stream = new PrintStream(errorBaos); //("c:\\test\\output.xml");
|
|
StandardLogger logger = new StandardLogger(stream);
|
|
if(e.getCause() instanceof net.sf.saxon.trans.XPathException) {
|
|
net.sf.saxon.trans.XPathException cause = (net.sf.saxon.trans.XPathException)e.getCause();
|
|
net.sf.saxon.lib.StandardErrorListener.printStackTrace(logger, cause.getXPathContext());
|
|
}else {
|
|
if(e.getCause() instanceof XPathException) {
|
|
ValidationException cause = (ValidationException)e.getCause();
|
|
net.sf.saxon.lib.StandardErrorListener.printStackTrace(logger, cause.getXPathContext());
|
|
}
|
|
}
|
|
try {
|
|
String errorText = errorBaos.toString("UTF8");
|
|
System.out.println("e.getCause(): " + e.getCause() + " \nerror text from StandardErrorListener:" + errorText);
|
|
} catch (UnsupportedEncodingException e1) {
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public static byte[] getBytes(String fileName) throws IOException {
|
|
File file = new File(fileName);
|
|
byte[] imgDataBa = new byte[(int)file.length()];
|
|
DataInputStream dataIs = new DataInputStream(new FileInputStream(file));
|
|
dataIs.readFully(imgDataBa);
|
|
//dataIs.close();
|
|
return imgDataBa;
|
|
}
|
|
}
|