April 20, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Optimizing Stylesheet Execution with the Java Transformation API for XML (TrAX)

  • August 27, 2002
  • By Jeff Ryan
  • Send Email »
  • More Articles »

Introduction

XSL (eXtensible Stylesheet Language) fulfills the need for transforming XML data into HTML, WML, or other XML formats. There is no easier way to parse and transform an XML document than XSL. However, the ease of use may come at a price. Because XSL is an interpreted language, there can be a performance tradeoff.

The Java Transformation API for XML (TrAX) can be used to invoke XSL stylesheets from Java programs. One of the nice features of TrAX is the ability to compile stylesheets and hold them in memory, dramatically improving performance.

This article will provide an introduction to some of the capabilities of TrAX:

  • We'll begin by using a simple example to demonstrate the basics of using the API.
  • Next, we'll learn how to compile stylesheets and keep them in memory to improve performance.
  • We'll conclude by demonstrating how to "hot deploy" stylesheets and refresh the compiled representation in memory.

A working understanding of Java and XML technology will be assumed.

A Simple Example

Let's dive right in with an example of using the Java Transformation API for XML. This example won't be optimized.

import javax.xml.transform.*;
import javax.xml.transform.stream.*;

public class SimpleTransform
{
    public static void main(String[] args) throws Exception
    {
        if (args.length != 3)
        {
            System.out.println("usage: SimpleTransform
                                <xmlFile> <xslFile> <outFile>");
            return;
        }
        String xmlFile = args[0];
        String xslFile = args[1];
        String outFile = args[2];
        
        StreamSource xslSource = new StreamSource(xslFile);

        TransformerFactory factory = 
             TransformerFactory.newInstance();

        Transformer transformer = 
             factory.newTransformer(xslSource);

        transformer.transform( new StreamSource(xmlFile)
                             , new StreamResult(outFile)
                             );
  }
}

SimpleTransform illustrates how the TrAX API can be used for file-based transformations. It takes an XML file and a stylesheet as inputs to create an output file representing the result of the transformation.

Notice that the StreamSource object is used to represent various types of input to the transformation. It is one of the implementations of the Source interface. StreamSource objects are constructed for the files containing the XSL stylesheet and the XML data to be transformed.

Similarly, the StreamResult object is used to represent the various types of output resulting from the transformation. It is one of the implementations of the Result interface. A StreamResult object is created for the output file of the transformation.

The TransformerFactory is used to get a Transformer object for the stylesheet. Its transform() method is used to transform the xml source into the result.

Important Note: The Transformer object provides a "per-thread" execution context for doing transformations. It is not thread safe. Although it is derived from the compiled stylesheet, it cannot be re-used between threads. Take it from someone who learned this the hard way.

Compiling Stylesheets

Now, let's build an example that will allow us to compile stylesheets and re-use them for multiple transformations. This will provide a significant performance boost to our transformations.

To explicitly compile stylesheets, we'll need to use the Templates object that TrAX provides. This object is a runtime representation of the transformation instructions. You can think of it as a compiled stylesheet. However, it is not represented in the file system like a .class file in Java. It is only represented in memory. Unlike the Transformer object, it is thread safe for concurrent usage once constructed.

We'll need to hold on to Templates objects for our stylesheets. Our strategy will be to hold a Map of Templates objects in a class variable. When transformations are requested, we'll first look into our Map and see if we already have a compiled stylesheet. If not, we'll add one.

import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import java.util.*;

public class XslTransformer
{
    private static Map CACHE = new Hashtable();
          // map of Templates objects
    private String xslFileName;
          // the filename of stylesheet and key to map
    private Transformer transformer; 

    public XslTransformer (String theXslFileName)
        throws TransformerConfigurationException
    {
        xslFileName  = theXslFileName;
        
        Templates templates = (Templates)CACHE.get(theXslFileName);
        if (templates == null)
        {
            TransformerFactory factory =
                       TransformerFactory.newInstance();

            templates = factory.newTemplates
                        (new StreamSource(xslFileName));

            CACHE.put(theXslFileName, templates);
        }
        transformer  = templates.newTransformer();
    }

    public void transform(Source xmlSource, Result result)
        throws TransformerException
    {
    transformer.transform(xmlSource, result);
    }

    public static void main(String[] args) throws Exception
    {
        if (args.length != 3)
        {
            System.out.println("usage: XslTransformer
                                <xmlFile> <xslFile> <outFile>");
            return;
        }
        String xmlFile = args[0];
        String xslFile = args[1];
        String outFile = args[2];
        
        XslTransformer xform = new XslTransformer(xslFile);
        xform.transform( new StreamSource(xmlFile)
                       , new StreamResult(outFile)
                       );
  }
}

In our constructor, the filename of the stylesheet is passed as an argument. We first look to see if we already have a Templates object for the stylesheet in the cache. If not, we ask the TransformerFactory for a new Templates object via newTemplates() rather than for a new Transformer object via newTransformer() as in the first example. Then we store the Templates object in the cache so that subsequent transformations using this stylesheet will use the version in the cache.





Page 1 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel