Let's start with perhaps the simplest program that can be
written. For this task, we will write a simple Java program that transforms a
static XML data file into HTML using an XSLT stylesheet. The key benefit of
beginning with a simple program is that it isolates problems with your
development environment, particularly CLASSPATH issues, before you move on to
more complex tasks.

Two versions of our Java program will be written, one for Xalan
and another for SAXON. A JAXP implementation will follow in the next section,
showing how the same code can be utilized for many different processors.

CLASSPATH Problems

CLASSPATH problems are a common culprit when your
code is not working, particularly with XML-related APIs. Since so many
tools now use XML, it is very likely that a few different DOM and SAX
implementations reside on your system. Before trying any of the
examples in this chapter, you may want to verify that older parsers
are not listed on your CLASSPATH.

More subtle problems can occur if an older
library resides in the Java 2 optional
packages directory. Any JAR file found in the jre/lib/ext directory is automatically available
to the JVM without being added to the CLASSPATH. You should look for
files such as jaxp.jar and parser.jar, which could contain older,
incompatible XML APIs. If you experience problems, remove all JAR
files from the optional packages directory.

Unfortunately, you will have to do some detective
work to figure out where the JAR files came from. Although Java 2
Version 1.3 introduced enhanced JAR features that included versioning
information, most of the JAR files you encounter probably will not
utilize this capability.

The design of this application is pretty simple. A single class
contains a main( ) method that performs the
transformation. The application requires two arguments: the XML file name
followed by the XSLT file name. The results of the transformation are simply
written to System.out. We will use the following
XML data for our example:

Since the filenames are passed as command-line parameters, the
application can be used with other XML and XSLT files. You might want to try
this out with one of the president examples from Chapters and 3.

The complete code for the Xalan implementation is listed in Example
5-1. As comments in the code indicate, this code was developed and tested
using Xalan 1.2.2, which is not the most recent XSLT processor from Apache.
Fully qualified Java class names, such as org.apache.xalan.xslt.XSLTProcessor, are used for all
Xalan-specific code.

TIP: A Xalan 2 example is not shown here because
Xalan 2 is compatible with Sun's JAXP. The JAXP version of this program
works with Xalan 2, as well as any other JAXP compatible
processor.

/**
* A simple demo of Xalan 1. This code was originally
* written using
* Xalan 1.2.2. It will not work with Xalan 2.
*/
public class SimpleXalan1 {

/**
* Accept two command line arguments: the name
* of an XML file, and the name of an XSLT
* stylesheet. The result of the transformation
* is written to stdout.
*/
public static void main(String[] args)
throws MalformedURLException, SAXException {
if (args.length != 2) {
System.err.println("Usage:");
System.err.println(" java " + SimpleXalan1.class.getName( )
+ " xmlFileName xsltFileName");
System.exit(1);
}

The code begins with the usual list of imports and the class
declaration, followed by a simple check to ensure that two command line
arguments are provided. If all is OK, then the XML file name and XSLT file
name are converted into system identifier values:

System identifiers are part of the XML specification and really
mean the same thing as a Uniform Resource Identifier (URI). A Uniform Resource
Locator (URL) is a specific type of URI and can be used for methods that
require system identifiers as parameters. From a Java programming perspective,
this means that a platform-specific filename such as C:/data/simple.xml needs to be converted to
file:///C:/data/simple.xml before it can be used by most XML APIs. The
code shown here does the conversion and will work on Unix, Windows, and other
platforms supported by Java. Although you could try to manually prepend the
filename with the literal string file:///, that may
not result in portable code. The documentation for java.io.File clearly states that its toURL( ) method generates a system-dependent URL, so the
results will vary when the same code is executed on a nonWindows platform. In
fact, on Windows the code actually produces a nonstandard URL (with a single
slash), although it does work within Java programs:
file:/C:/data/simple.xml.

Now that we have system identifiers for our two input files, an
instance of the XSLT processor is created:

XSLTProcessor is an interface, and
XSLTProcessorFactory is a factory for creating new
instances of classes that implement it. Because Xalan is open source software,
it is easy enough to determine that XSLTEngineImpl
is the class that implements the XSLTProcessor
interface, although you should try to avoid code that depends on the specific
implementation.

The next few lines of code create XSLTInputSource objects, one for the XML file and another for the XSLT file:

XSLTInputSource is a subclass of
org.xml.sax.InputSource, adding the ability to read
directly from a DOM Node. XSLTInputSource has the ability to read XML or XSLT data
from a system ID, java.io.InputStream, java.io.Reader, org.w3c.dom.Node, or an existing InputSource. As shown in the code, the source of the data
is specified in the constructor. XSLTInputSource
also has a no-arg constructor, along with getter/setter methods for each of
the supported data source types.

An instance of XSLTResultTarget is
created next, sending the result of the transformation to System.out:

In a manner similar to XSLTInputSource, the XSLTResultTarget can also be wrapped around an instance
of org.w3c.dom.Node, an OutputStream or Writer, a filename (not a system ID!), or an instance of org.xml.sax.DocumentHandler.

The final line of code simply instructs the processor to perform
the transformation:

For comparison's sake, a SAXON 5.5.1 implementation is presented
in Example
5-2. As you scan through the code, you will notice the word "trax"
appearing in the Java packages. This is an indication that Version 5.5.1 of
SAXON was moving towards something called Transformation API for XML (TrAX).
More information on TrAX is coming up in the JAXP discussion. In a nutshell,
TrAX provides a uniform API that should work with any XSLT processor.

/**
* A simple demo of SAXON. This code was originally written using
* SAXON 5.5.1.
*/
public class SimpleSaxon {

/**
* Accept two command line arguments: the name of an XML file, and
* the name of an XSLT stylesheet. The result of the transformation
* is written to stdout.
*/
public static void main(String[] args)
throws MalformedURLException, IOException, SAXException {
if (args.length != 2) {
System.err.println("Usage:");
System.err.println(" java " + SimpleSaxon.class.getName( )
+ " xmlFileName xsltFileName");
System.exit(1);
}

// create a transformer that can be used for a single transformation
com.icl.saxon.trax.Transformer trans = templates.newTransformer( );
trans.transform(xmlInputSource, result);
}
}

The SAXON implementation starts exactly as the Xalan
implementation does. Following the class declaration, the command-line
parameters are validated and then converted to system IDs. The XML and XSLT
system IDs are then wrapped in org.xml.sax.InputSource objects as follows:

This code is virtually indistinguishable from the Xalan code,
except Xalan uses XSLTInputSource instead of InputSource. As mentioned before, XSLTInputSource is merely a subclass of InputSource that adds support for reading from a DOM
Node. SAXON also has the ability to read from a DOM
node, although its approach is slightly different.

Creating a Result object sets up the destination for the XSLT result tree, which is directed to System.out in this example:

com.icl.saxon.trax.Result result =
new com.icl.saxon.trax.Result(System.out);

The XSLT stylesheet is then compiled, resulting in an object
that can be used repeatedly from many concurrent threads:

In a typical XML and XSLT web site, the XML data is generated
dynamically, but the same stylesheets are used repeatedly. For instance,
stylesheets generating common headers, footers, and navigation bars will be
used by many pages. To maximize performance, you will want to process the
stylesheets once and reuse the instances for many clients at the same time.
For this reason, the thread safety that Templates
offers is critical.

An instance of the Transformer class
is then created to perform the actual transformation. Unlike the stylesheet
itself, the transformer cannot be shared by many clients and is not
thread-safe. If this was a servlet implementation, the Transformer instance would have to be created with each
invocation of doGet or doPost. In our example, the code is as follows: