Introduction to JAXP 1.1
TrAX was a great idea, and the original work and concepts behind it
were absorbed into JAXP Version 1.1. If you search for TrAX on the
Web and get the feeling that the effort is waning, this is only
because focus has shifted from TrAX to JAXP. Although the name has
changed, the concept has not: JAXP provides a standard Java interface
to many XSLT processors, allowing you to choose your favorite
underlying implementation while retaining portability.
First released in March 2000, Sun's JAXP 1.0 utilized XML 1.0, XML
Namespaces 1.0, SAX 1.0, and DOM Level 1. JAXP is a standard extension
to Java, meaning that Sun provides a specification through its Java
Community Process (JCP) as well as a reference implementation.
JAXP 1.1 follows the same basic design philosophies of JAXP 1.0,
adding support for DOM Level 2, SAX 2, and XSLT 1.0. A tool like
JAXP is necessary because the XSLT specification defines only a
transformation language; it says nothing about how to write a Java
XSLT processor. Although they all perform the same basic tasks,
every processor uses a different API and has its own set of
programming conventions.
JAXP is not an XML parser, nor is it an XSLT processor. Instead, it
provides a common Java interface that masks differences between
various implementations of the supported standards. When using JAXP,
your code can avoid dependencies on specific vendor tools, allowing
flexibility to upgrade to newer tools when they become available.
The key to JAXP's design is the concept of plugability layers.
These layers provide consistent Java interfaces to the underlying SAX,
DOM, and XSLT implementations. In order to utilize one of these APIs,
you must obtain a factory class without hardcoding Xalan or SAXON
code into your application. This is accomplished via a lookup
mechanism that relies on Java system properties. Since three separate
plugability layers are used, you can use a DOM parser from one vendor,
a SAX parser from another vendor, and yet another XSLT processor from
someone else. In reality, you will probably need to use a DOM parser
compatible with your XSLT processor if you try to transform the DOM
tree directly. Figure 5-1
illustrates the high-level architecture of JAXP 1.1.
Figure 5-1.
JAXP 1.1 architecture
|
|
As shown, application code does not deal directly with specific parser
or processor implementations, such as SAXON or Xalan. Instead, you
write code against abstract classes that JAXP provides. This level
of indirection allows you to pick and choose among different
implementations without even recompiling your application.
The main drawback to an API such as JAXP is the "least common
denominator" effect, which is all too familiar to AWT programmers.
In order to maximize portability, JAXP mostly provides functionality
that all XSLT processors support. This means, for instance, that
Xalan's custom XPath APIs are not included in JAXP. In order to use
value-added features of a particular processor, you must revert to
nonportable code, negating the benefits of a plugability layer.
Fortunately, most common tasks are supported by JAXP, so reverting
to implementation-specific code is the exception, not the rule.
Although the JAXP specification does not define an XML parser or XSLT
processor, reference implementations do include these tools. These
reference implementations are open source Apache XML tools,
[1]
so complete source code is available.
JAXP 1.1 Implementation
You guessed it--we will now reimplement the simple example using
Sun's JAXP 1.1. Behind the scenes, this could use any
JAXP 1.1-compliant XSLT processor; this code was developed and
tested using Apache's Xalan 2 processor.
Example 5-3 contains the complete
source code.
Example 5-3:
SimpleJaxp.java
package chap5;
import java.io.*;
/**
* A simple demo of JAXP 1.1
*/
public class SimpleJaxp {
/**
* 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 javax.xml.transform.TransformerException {
if (args.length != 2) {
System.err.println("Usage:");
System.err.println(" java " + SimpleJaxp.class.getName( )
+ " xmlFileName xsltFileName");
System.exit(1);
}
File xmlFile = new File(args[0]);
File xsltFile = new File(args[1]);
javax.xml.transform.Source xmlSource =
new javax.xml.transform.stream.StreamSource(xmlFile);
javax.xml.transform.Source xsltSource =
new javax.xml.transform.stream.StreamSource(xsltFile);
javax.xml.transform.Result result =
new javax.xml.transform.stream.StreamResult(System.out);
// create an instance of TransformerFactory
javax.xml.transform.TransformerFactory transFact =
javax.xml.transform.TransformerFactory.newInstance( );
javax.xml.transform.Transformer trans =
transFact.newTransformer(xsltSource);
trans.transform(xmlSource, result);
}
}
As in the earlier examples, explicit package names are used in the
code to point out which classes are parts of JAXP. In future
examples, import statements will be favored because
they result in less typing and more readable code. Our new program
begins by declaring that it may throw TransformerException:
public static void main(String[] args)
throws javax.xml.transform.TransformerException {
This is a general-purpose exception representing anything that might
go wrong during the transformation process. In other processors,
SAX-specific exceptions are typically propagated to the caller. In
JAXP, TransformerException can be wrapped around any
type of Exception object that various XSLT processors
may throw.
Next, the command-line arguments are converted into File
objects. In the SAXON and Xalan examples, we created a system ID for
each of these files. Since JAXP can read directly from a
File object, the extra conversion to a URI is not needed:
File xmlFile = new File(args[0]);
File xsltFile = new File(args[1]);
javax.xml.transform.Source xmlSource =
javax.xml.transform.stream.StreamSource(xmlFile);
javax.xml.transform.Source xsltSource =
new javax.xml.transform.stream.StreamSource(xsltFile);
The Source interface is used to read both the XML file
and the XSLT file. Unlike the SAX InputSource class or
Xalan's XSLTInputSource class, Source is
an interface that can have many implementations. In this simple
example we are using StreamSource, which has the ability
to read from a File object, an InputStream,
a Reader, or a system ID. Later we will examine
additional Source implementations that use SAX and DOM
as input. Just like Source, Result is an
interface that can have several implementations. In this example,
a StreamResult sends the output of the transformations
to System.out:
javax.xml.transform.Result result =
new javax.xml.transform.stream.StreamResult(System.out);
Next, an instance of TransformerFactory is created:
javax.xml.transform.TransformerFactory transFact =
javax.xml.transform.TransformerFactory.newInstance( );
The TransformerFactory is responsible for creating
Transformer and Template objects. In our
simple example, we create a Transformer object:
javax.xml.transform.Transformer trans =
transFact.newTransformer(xsltSource);
Transformer objects are not thread-safe, although they
can be used multiple times. For a simple example like this, we will
not encounter any problems. In a threaded servlet environment,
however, multiple users cannot concurrently access the same
Transformer instance. JAXP also provides a
Templates interface, which represents a stylesheet
that can be accessed by many concurrent threads.
The transformer instance is then used to perform the actual
transformation:
trans.transform(xmlSource, result);
This applies the XSLT stylesheet to the XML data, sending the result
to System.out.
Footnote:
New on the Java Boutique:
New Review:
Time Management Made Easy with the Quartz Enterprise Job Scheduler
Why not just use the Java timer API? This open source scheduling
API boasts simplicity, ease-of-integration, a well-rounded feature
set, and it's free!
New Applet:
Reverse Complement
Reverse Complement is a simple applet that converts DNA or RNA
sequences into three useful formats.
Elsewhere on internet.com:
WebDeveloper Java
Lots of Java information on webdeveloper.com
WDVL Java
Thorough Java resource at the Web Developer's Virtual Library.
ScriptSearch Java
Hundreds of free Java code files to download.
jGuru: Your View of the Java Universe
Customizable portal with online training, FAQs, regular news updates, and tutorials.
|