Saturday, October 07, 2017

Using XSLT 2.0 with Java and Saxon

In my previous post, I showed how you can split a string using the tokenize function in XSLT 2.0. In order to run an XSLT 2.0 stylesheet in Java, you need a transformer that supports XSLT 2.0. Unfortunately, the default JAXP transformer (com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl) does not. Instead, use Saxon, which supports both XSLT 2.0 and 3.0.

The class below shows how you can perform an XSL transformation in Java, using Saxon and the JAXP interface:

import java.io.StringReader;
import java.io.StringWriter;

import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

public class XSLTransformer {

  private final Templates templates;

  public XSLTransformer(final String xslFileName) throws Exception {
    templates = new net.sf.saxon.BasicTransformerFactory().newTemplates(
        new StreamSource(XSLTransformer.class.getClassLoader()
                             .getResourceAsStream(xslFileName)));
  }

  public String transform(final String xml) throws Exception {
    final Transformer transformer = templates.newTransformer();
    final StringWriter writer = new StringWriter();
    transformer.transform(new StreamSource(new StringReader(xml)),
                          new StreamResult(writer));
    return writer.toString();
  }
}

An alternative to the JAXP interface is to use Saxon's own s9api interface, which is more robust:

import java.io.StringReader;
import java.io.StringWriter;

import javax.xml.transform.stream.StreamSource;

import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.XsltExecutable;
import net.sf.saxon.s9api.XsltTransformer;

public class SaxonTransformer {

  private final Processor processor;
  private final XsltExecutable xsltExec;

  public SaxonTransformer(final String xslFileName) throws SaxonApiException {
    processor = new Processor(false);
    xsltExec = processor.newXsltCompiler().compile(new StreamSource(
        XSLTransformer.class.getClassLoader().getResourceAsStream(xslFileName)));
  }

  public String transform(final String xml) throws Exception {
    final XsltTransformer transformer = xsltExec.load();
    transformer.setSource(new StreamSource(new StringReader(xml)));
    final StringWriter writer = new StringWriter();
    transformer.setDestination(processor.newSerializer(writer));
    transformer.transform();
    return writer.toString();
  }
}

No comments:

Post a Comment