com.elsevier.spark_xml_utils.xslt.XSLTProcessor.java Source code

Java tutorial

Introduction

Here is the source code for com.elsevier.spark_xml_utils.xslt.XSLTProcessor.java

Source

/*
 * Copyright (c)2015 Elsevier, Inc.
    
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package com.elsevier.spark_xml_utils.xslt;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map.Entry;

import javax.xml.transform.stream.StreamSource;

import net.sf.saxon.s9api.DocumentBuilder;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.QName;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.Serializer;
import net.sf.saxon.s9api.XdmValue;
import net.sf.saxon.s9api.XsltCompiler;
import net.sf.saxon.s9api.XsltExecutable;
import net.sf.saxon.s9api.XsltTransformer;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.CharEncoding;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Class that provides xml transforming capabilities  (via xslt) for xml passed as a String.
 * 
 * @author Darin McBeath
 * 
 */
public class XSLTProcessor implements Serializable {

    private static final long serialVersionUID = -5320116690116312347L;

    // Logger
    private static Log log = LogFactory.getLog(XSLTProcessor.class);

    // Member variables
    private HashMap<String, Object> featureMappings = null;
    private String stylesheet = null;
    private transient Processor proc = null;
    private transient Serializer serializer = null;
    private transient ByteArrayOutputStream baos = null;
    private transient XsltTransformer trans = null;
    private transient DocumentBuilder builder = null;

    /**
     * Create an instance of XSLTProcessor.
     *  
     * @param stylesheet 
     * @param featureMappings Processor feature mappings
     * @throws XSLTException
     */
    private XSLTProcessor(String stylesheet, HashMap<String, Object> featureMappings) throws XSLTException {

        this.stylesheet = stylesheet;
        this.featureMappings = featureMappings;

    }

    /**
     * Restore the serialized object and then do a one time initialization to improve
     * performance for repetitive invocations of transformations.  We need to
     * initialize the transient variables.
     * 
     * @param inputStream
     * @throws IOException
     * @throws ClassNotFoundException
     * @throws XSLTException 
     */
    private void readObject(ObjectInputStream inputStream)
            throws IOException, ClassNotFoundException, XSLTException {

        inputStream.defaultReadObject();
        init();

    }

    /**
     * Get an instance of XSLTProcessor and then do a one time initialization to improve
     * performance for repetitive invocations of transformations.
     * 
     * @param stylesheet
     * @return XSLTProcessor
     * @throws XSLTException 
     */
    public static XSLTProcessor getInstance(String stylesheet) throws XSLTException {

        XSLTProcessor proc = new XSLTProcessor(stylesheet, null);
        proc.init();
        return proc;

    }

    /**
     * Get an instance of XSLTProcessor and then do a one time initialization to improve
     * performance for repetitive invocations of transformations.
     * 
     * @param stylesheet
     * @param featureMappings Processor feature mappings
     * @return XSLTProcessor
     * @throws XSLTException 
     */
    public static XSLTProcessor getInstance(String stylesheet, HashMap<String, Object> featureMappings)
            throws XSLTException {

        XSLTProcessor proc = new XSLTProcessor(stylesheet, featureMappings);
        proc.init();
        return proc;

    }

    /**
     * Initialization to improve performance for repetitive invocations of transformations.
     * 
     * @throws XSLTException
     */
    private void init() throws XSLTException {

        try {

            // Get the processor
            proc = new Processor(false);

            // Set any specified configuration properties for the processor
            if (featureMappings != null) {
                for (Entry<String, Object> entry : featureMappings.entrySet()) {
                    proc.setConfigurationProperty(entry.getKey(), entry.getValue());
                }
            }

            // Get the xslt compiler
            XsltCompiler xsltCompiler = proc.newXsltCompiler();

            // Get the document builder (used for params)
            builder = proc.newDocumentBuilder();

            // Set the uri resolver (for imported/included stylesheets)
            xsltCompiler.setURIResolver(new S3URIResolver());

            // Compile the stylesheet
            XsltExecutable exp = xsltCompiler
                    .compile(new StreamSource(IOUtils.toInputStream(stylesheet, CharEncoding.UTF_8)));

            // Set up the output for the transformation
            baos = new ByteArrayOutputStream();
            serializer = proc.newSerializer(baos);
            serializer.setOutputStream(baos);
            // Appears ok to always set output property to xml
            serializer.setOutputProperty(Serializer.Property.METHOD, "xml");
            serializer.setOutputProperty(Serializer.Property.OMIT_XML_DECLARATION, "yes");
            serializer.setProcessor(proc);
            trans = exp.load();
            trans.setDestination(serializer);

        } catch (SaxonApiException e) {

            log.error("Problems creating an XSLTProcessor.  " + e.getMessage(), e);
            throw new XSLTException(e.getMessage());

        } catch (IOException e) {

            log.error("Problems creating an XSLTProcessor.  " + e.getMessage(), e);
            throw new XSLTException(e.getMessage());

        }

    }

    /**
     * Set the output method (the default is xml).
     * @param method
     */
    public void setOutputMethod(String method) {
        serializer.setOutputProperty(Serializer.Property.METHOD, method);
    }

    /**
     * Transform the content.
     * 
     * @param content the xml to be transformed
     * @return transformed content
     * @throws XSLTException
     */
    public String transform(String content) throws XSLTException {

        // Apply transformation
        return transform(content, new HashMap<String, String>());

    }

    /**
     * Transform the content.
     * 
     * @param content the xml to be transformed
     * @return transformed content
     * @throws XSLTException
     */
    public String transform(InputStream content) throws XSLTException {

        // Apply transformation
        return transform(new StreamSource(content), new HashMap<String, String>());

    }

    /**
     * Transform the content.
     * 
     * @param content the xml to be transformed
     * @param stylesheetParams HashMap of stylesheet params
     * @return transformed content
     * @throws XSLTException
     */
    public String transform(String content, HashMap<String, String> stylesheetParams) throws XSLTException {

        try {

            // Create streamsource for the content
            StreamSource contentSource = new StreamSource(IOUtils.toInputStream(content, CharEncoding.UTF_8));

            // Apply transformation
            return transform(contentSource, stylesheetParams);

        } catch (IOException e) {

            log.error("Problems transforming the content. " + e.getMessage(), e);
            throw new XSLTException(e.getMessage());

        }

    }

    /**
     * Transform the content.
     * @param content the xml to be transformed
     * @param stylesheetParams HashMap of stylesheet params
     * @return transformed content
     * @throw XSLTException
     */
    private String transform(StreamSource content, HashMap<String, String> stylesheetParams) throws XSLTException {

        try {

            //Reset the serializer
            serializer.close();
            baos.reset();

            // Set stylesheet parameters (if any were specified)
            for (Entry<String, String> entry : stylesheetParams.entrySet()) {
                XdmValue xdmValue = builder
                        .build(new StreamSource(IOUtils.toInputStream(entry.getValue(), CharEncoding.UTF_8)));
                trans.setParameter(new QName("", entry.getKey()), xdmValue);
            }

            // Set the content to use for the transformation
            trans.setSource(content);

            // Transform the content
            trans.transform();

            // Return the transformed content
            return new String(baos.toByteArray(), CharEncoding.UTF_8);

        } catch (IOException e) {

            log.error("Problems transforming the content.  " + e.getMessage(), e);
            throw new XSLTException(e.getMessage());

        } catch (SaxonApiException e) {

            log.error("Problems transforming the content.  " + e.getMessage(), e);
            throw new XSLTException(e.getMessage());

        }

    }

}