17.1 Running an XSLT Processor from Java

Java Version 1.4 standard or enterprise edition comes standard with JAXP. JAXP includes the APIs you'll need to create an XSLT processor. You must use Version 1.4 or a later Java Runtime Environment (JRE) to run this example as it is described (more on this later). You can download the latest Java JRE or Software Development Kit (SDK) from http://java.sun.com.

To write a processor with JAXP, you need two extension packages: javax.xml.transform and javax.xml.transform.stream. There are other packages available to help you do more things in XSLT, but we'll focus on these packages for the sake of simplicity. You can consult the API documentation for these packages at http://java.sun.com/j2se/1.4/docs/api/index.html.

17.1.1 The Moxie Source Code

In examples/ch17, you will find the source code for the Moxie XSLT processor, Moxie.java. This program has only 68 lines because the heavy lifting is done by classes from Java extension packages.

Example 17-1 lists the source code.

Example 17-1. The Moxie code for running an XSLT processor
/*  * Moxie JAXP XSLT processor  */     import java.io.File; import java.io.FileOutputStream; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource;     public class Moxie {         public static void main(String[  ] args) throws Exception {            /* Output file flag */        boolean file = false;            /* Default system property for Xalan processor */        System.setProperty("javax.xml.transform.TransformerFactory",            "org.apache.xalan.processor.TransformerFactoryImpl");            /* Usage strings */        String info = "Moxie JAXP XSLT processor";        String usage = "\nUsage: java -jar moxie.jar";        String parms = " source stylesheet [result]";            /* Test arguments */        if (args.length =  = 0) {            System.out.println(info + usage + parms);            System.exit(1);        } else if (args.length =  = 3) {            file = true;        } else if (args.length > 3) {            System.out.println("Too many arguments; exit.");            System.exit(1);        }            /* XML source document and stylesheet */        File source = new File(args[0]);        File stylesheet = new File(args[1]);            /* Set up source and result streams */        StreamSource src = new StreamSource(source);        StreamSource style = new StreamSource(stylesheet);        StreamResult out;        if (file) {            FileOutputStream outFile = new FileOutputStream(args[2]);            out = new StreamResult(outFile);        } else {            out = new StreamResult(System.out);        }            /* Create transformer */        TransformerFactory factory = TransformerFactory.newInstance(  );        Transformer xf = factory.newTransformer(style);            /* Set output encoding property */        xf.setOutputProperty(OutputKeys.ENCODING, "US-ASCII"); // encoding        xf.setOutputProperty(OutputKeys.INDENT, "yes");        // indent            /* Perform the transformation */        xf.transform(src, out);         }     }

To an experienced Java programmer, this code should readily make sense, but just to make sure the code is comprehensible, I've provided the following discussions that dissect each part of the program.

17.1.2 Looking at the Moxie Code

Moxie imports seven classes at the beginning of the program:

import java.io.File; import java.io.FileOutputStream; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource;

The first two classes are from the java.io package. The three classes that follow are from the javax.xml.transform extension package, and the two after that are from javax.xml.transform.stream.

The File class handles the input files (the source XML document and the stylesheet), and FileOutputStream helps write an output file from the result tree of the transformation. TransformerFactory assists in creating a new instance of Transformer class, which actually performs the transformations. OutputKeys lets you submit values to the transformer that normally come from attributes on the output element, such as the method or encoding attributes. The remaining classes, StreamResult and StreamSource, are holders for streams representing the result and source trees, respectively.

Next in the program, the class Moxie is defined as well as the main( ) method that makes everything happen. The first thing that's done is to create a boolean called file that acts as a flag to tell the processor whether output will be sent to a file:

/* Output file flag */  boolean file = false;

This flag is set to true if a third argument appears on the command line (explained shortly).

The next thing that you see in the program is a call to the setProperty( ) method from the System class:

/* Default system property for the Xalan processor */ System.setProperty("javax.xml.transform.TransformerFactory", "org.apache.xalan.processor.TransformerFactoryImpl");

This method is not required, but I've included it to illustrate a point. The Xalan processor from Apache is the default XSLT engine underneath JAXP's hood. This system property sets the transformation engine to Xalan for JAXP explicitly, but it is already done automatically, so it is unnecessary. It is there so that if you want to change the system property, you can easily do so. The system property for Xalan is org.apache.xalan.processor.TransformerFactoryImpl. You can change the property to Saxon Version 7 or above with the property net.sf.saxon.TransformerFactoryImpl, or you can change it to jd.xslt with jd.xml.xslt.trax.TransformerFactoryImpl. If you change the system property to Saxon 7, you have to add saxon7.jar to the classpath; if you change it to jd.xslt, you need to add jdxslt.jar.

The arguments to main( ) are evaluated with an if statement. The three possible command-line arguments all represent files:

  1. The first argument (args[0]) represents the XML source document that you want to transform.

  2. The second argument (args[1]) is the XSLT stylesheet for performing the transformation.

  3. The third argument (args[2]) is optional and, if used, represents the name of the file where the result tree will be stored. If absent, the result tree will appear on System.out (standard output or the screen). The file variable is of type boolean and indicates whether this third argument is present; if so, file is set to true (false by default) and a file will be written for the result tree.

These arguments are interpreted as files with the help of two File class constructors. Constructors for two StreamSource objects and two StreamResult objects are then called:

StreamSource src = new StreamSource(source); StreamSource style = new StreamSource(stylesheet); StreamResult out; if (file) {     FileOutputStream outFile = new FileOutputStream(args[2]);     out = new StreamResult(outFile); } else {     out = new StreamResult(System.out); }

This tells the program to interpret the input files as streams for the benefit of the transformer. (You could also represent these files as DOM documents by using the DOMSource class from javax.xml.transform.dom, or as SAX events with SAXSource class from javax.xml.transform.sax.) An if-else statement provides a little logic using the Boolean file that either sends the result stream to the screen or to a file.

After that, a factory is used to call a constructor and then create a new transformer:

TransformerFactory factory = TransformerFactory.newInstance(  ); Transformer xf = factory.newTransformer(style);

Notice that the new transformer takes the stylesheet as an argument (style).

Next, the output encoding for the result tree is set to US-ASCII, and indention is set to yes by calling the setOutputProperty( ) method twice:

xf.setOutputProperty(OutputKeys.ENCODING, "US-ASCII"); // encoding xf.setOutputProperty(OutputKeys.INDENT, "yes");        // indent

The setOutputProperty( ) method comes from the Transformer class. The OutputKeys class, discussed earlier, provides fields, such as ENCODING and INDENT, that correlate with the attributes of the XSLT output element (like encoding and indent). These method calls have the same effect as using the output element in a stylesheet like this:

<xsl:output encoding="US-ASCII" indent="yes"/>

Calling setOutputProperty( ) with ENCODING and a value of US-ASCII, and calling INDENT with yes, replaces the values of the encoding and indent attributes on the stylesheet's output element.

Finally, the program performs the actual transformation using the transform( ) method of the Transformer class:

xf.transform(src, out);

The first argument, src, is the source stream derived from the input file, and the second argument is the result tree. The stylesheet has already been associated with the instance of Transformer earlier in the code.

17.1.3 Running Moxie

To run Moxie, you need to have at least a JRE installed for Version 1.4 or later. A JRE is a Java Runtime Environment, a Java Virtual Machine (JVM) with core classes. If you want to change the code in Moxie.java and then recompile it, you need a Java 2 1.4 SDK to get the javac compiler, but to only run it, you just need a JRE.

To find out what version your JRE is, type the following line at a command-line prompt:

java -version

When I type this on my system, I get the following response:

java version "1.4.1_01" Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_01-b01) Java HotSpot(TM) Client VM (build 1.4.1_01-b01, mixed mode)

If you get back something like this, it means you're in good shape. Now, while in examples/ch17, type this line:

java -jar moxie.jar

or this line:

java Moxie

You will get some usage information in response:

Moxie JAXP XSLT processor Usage: java -jar moxie.jar source stylesheet [result]

If you've gotten this far without errors, you are ready to perform a transformation. The document test.xml contains a list of methods from the Transformer class, and test.xsl transforms it:

java -jar moxie.jar test.xml test.xsl

The result should look like this:

<?xml version="1.0" encoding="US-ASCII"?> <methods> <method>clearParameters(  )</method> <method>getErrorListener(  )</method> <method>getOutputProperties(  )</method> <method>getOutputProperty(String name)</method> <method>getParameter(String name)</method> <method>getURIResolver(  )</method> <method>setErrorListener(ErrorListener listener)</method> <method>setOutputProperties(Properties oformat)</method> <method>setOutputProperty(String name, String value)</method> <method>setParameter(String name, Object value)</method> <method>setURIResolver(URIResolver resolver)</method> <method>transform(Source xmlSource, Result outputTarget)</method> </methods>

By default, the transformer uses UTF-8 for output encoding, but setOutputProperty( ) overrides the default with US-ASCII, as you can see in the XML declaration of the result tree. The setOutputProperty( ) method also turns on indentation without it, all elements in the result would run together.

If you'd like, you can also send the result tree to a file rather than to the screen. To accomplish this, you must submit a filename as the third argument on the command line, as you see here:

java -jar moxie.jar test.xml test.xsl moxie.xml

When you enter this line, Moxie writes the result tree to a file in the current directory using the FileOutputStream class.

You will also find a pair of files in examples/ch17 that will help you: moxie.bat is a Windows batch file and moxie.sh is a Unix shell script. You can use either of them to reduce typing. For example, to perform the previous transformation at a Unix shell prompt, just type:

moxie.sh test.xml test.xsl moxie.xml

Or, at a Windows command prompt, type:

moxie test.xml test.xsl moxie.xml

You can alter the source file Moxie.java to your heart's content. For more information on JAXP, check the Javadocs for the following packages: javax.xml.parsers, javax.xml.transform, javax.xml.transform.dom, javax.xml.transform.sax, and javax.xml.transform.stream.

17.1.4 Compiling Moxie

If you alter Moxie.java, you will have to recompile it in order to get the new version to run. With Java Version 1.4 SDK installed, the Java compiler javac should be available to you if the compiler is in your path variable. Find out whether javac is there by typing the following on a command line:

javac

If the compiler is available, you will see usage information on the screen:

Usage: javac <options> <source files> where possible options include:   -g                        Generate all debugging info   -g:none                   Generate no debugging info   -g:{lines,vars,source}    Generate only some debugging info   -O                        Optimize; may hinder debugging or enlarge class file   -nowarn                   Generate no warnings   -verbose                  Output messages about what the compiler is doing   -deprecation              Output source locations where deprecated APIs are used   -classpath <path>         Specify where to find user class files   -sourcepath <path>        Specify where to find input source files   -bootclasspath <path>     Override location of bootstrap class files   -extdirs <dirs>           Override location of installed extensions   -d <directory>            Specify where to place generated class files   -encoding <encoding>      Specify character encoding used by source files   -source <release>         Provide source compatibility with specified release   -target <release>         Generate class files for specific VM version   -help                     Print a synopsis of standard options

To compile Moxie, enter:

javac Moxie.java

If the program compiles without errors, the compilation produces the class file Moxie.class. This class file contains the byte codes that the JRE interprets to run the program on your particular platform. You can then run the program by using this line:

java Moxie test.xml test.xsl

You can also recreate your JAR file with the jar tool using this command:

jar cfm moxie.jar META-INF/MANIFEST.MF Moxie.class

This line uses the jar tool to create (c) a new file (f) moxie.jar with a manifest file (m) called META-INF/MANIFEST.MF and with the class file Moxie.class. The manifest file conveys information to the Java interpreter when, for example, the interpreter is run with the -jar option. One such bit of information is what class holds the main( ) method. This information is passed on with the following field and value pair from the manifest file:

Main-Class: Moxie

You need this field and value in order for this command to work:

java -jar moxie.jar

Actually, there is an easier way to perform all these steps at once by using the Ant build tool.

17.1.5 Using Ant

Ant is a Java-based build tool sponsored by Apache (see http://ant.apache.org). Ant is easy to use and a time saver. If you are not familiar with Ant but would like to give it a try, go to http://ant.apache.org/resources.html for a list of FAQs, articles, presentations, and books that will help you get up to speed. A build file called build.xml is in examples/ch17 and is available to you for building Moxie with Ant.

The file build.xml also depends on the ant.properties file (which is also in examples/ch17) to provide the location of the base directory where the builds take place. The base directory on Windows is assumed to be base.dir=c:/learningxslt/examples/ch17/; change the base directory to the correct location.

Assuming that you have downloaded Ant (I'm using Version 1.5.3), installed it, and placed it in your path, you should be able to type the following on a command line:

ant -version

You will get this information on your screen:

Apache Ant version 1.5.3 compiled on April 9 2003

If you type the word ant alone on a command line on Windows, while the current directory is examples/ch17, Ant automatically picks up the build file build.xml and performs the build, reporting the following to the screen:

Buildfile: build.xml     init:    [delete] Deleting: C:\learningxslt\examples\ch16\moxie.jar     compile:     [javac] Compiling 1 source file     jar:       [jar] Building jar: C:\LearningXSLT\examples\ch16\moxie.jar     java:      [java] Moxie JAXP XSLT processor      [java] Usage: java -jar moxie.jar source stylesheet [result]      [java] Java Result: 1     zip:       [zip] Building zip: C:\LearningXSLT\examples\ch16\moxie.zip     finish:      [copy] Copying 1 file to C:\LearningXSLT\examples\ch16\Backup     BUILD SUCCESSFUL Total time: 7 seconds

In just one step, the build process defined by build.xml performs the following tasks:

  1. Deletes the old moxie.jar file.

  2. Compiles Moxie.java, if it has changed since the last build.

  3. Builds a new JAR file for Moxie (moxie.jar).

  4. Runs the Moxie program without arguments.

  5. Creates a zip file that stores all of Moxie's resources in one spot (moxie.zip).

  6. Copies moxie.zip to the directory examples/ch17/Backup.

Ant is growing in popularity and is being integrated into IDEs like jEdit, VisualAge, and even WebSphere (for links, see http://ant.apache.org/manual/ide.html). Ant also has tasks that do XSLT processing. Check it out at http://ant.apache.org/manual/CoreTasks/style.html. If you work much with Java, learning Ant will be well worth your time.

17.1.6 Other Java Resources

Eric Burke's Java and XSLT (O'Reilly) is a good place to turn for help with using XSLT with JAXP. Brett McLaughlin's Java & XML, Second Edition (O'Reilly) provides solid help with using Java APIs such as JAXP, SAX, DOM, JDOM, with XML. I also recommend that you get acquainted with Elliotte Rusty Harold's Java API XML Object Model or XOM, available for download from http://www.xom.nu. XOM is simple, easy to learn, and has taken many lessons from earlier APIs. XOM also has a package (nu.xom.xslt) for connecting to XSLT processors that support JAXP.

I'll now turn my attention to writing a simple XSLT processor with C#.



Learning XSLT
Learning XSLT
ISBN: 0596003277
EAN: 2147483647
Year: 2003
Pages: 164

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net