XSLT Processing with Java
Pages: 1, 2, 3, 4, 5, 6, 7, 8, 9
The Transformer Class
As shown in Example 5-3, a Transformer object can be obtained from the TransformerFactory as follows:
javax.xml.transform.TransformerFactory transFact = javax.xml.transform.TransformerFactory.newInstance( );
javax.xml.transform.Transformer trans = transFact.newTransformer(xsltSource);
The Transformer instance is wrapped
around an XSLT stylesheet and allows you to perform as many transformations as
you wish. The main caveat is thread safety, because many threads cannot use a
single Transformer instance concurrently. For each
transformation, invoke the transform method:
abstract void transform(Source xmlSource, Result outputTarget) throws TransformerException
|
System properties can also be specified in Ant build files. |
This method is abstract because the TransformerFactory actually returns a subclass of Transformer that does the actual work. The Source interface defines where the XML data comes from and the Result interface specifies where the transformation result is sent. The TransformerException will be thrown if anything goes
wrong during the transformation process and may contain the location of the
error and a reference to the original exception. The ability to properly
report the location of the error is entirely dependent upon the quality of the
underlying XSLT transformer implementation's error reporting. We will talk
about specific classes that implement the Source
and Result interfaces later in this chapter.
Aside from actually performing the transformation, the Transformer implementation allows you to set output
properties and stylesheet parameters. In XSLT, a stylesheet parameter is
declared and used as follows:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:param name="image_dir" select="'images'"/>
<xsl:template match="/">
<html>
<body>
<h1>Stylesheet Parameter Example</h2>
<img src="{$image_dir}/sample.gif"/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
The <xsl:param> element
declares the parameter name and an optional select
attribute. This attribute specifies the default value if the stylesheet
parameter is not provided. In this case, the string 'images' is the default value and is enclosed in
apostrophes so it is treated as a string instead of an XPath expression.
Later, the image_dir variable is referred to with
the attribute value template syntax: {$image_dir}.
Passing a variable for the location of your images is a common technique for a web application because your development environment might use a different directory name than your production web server. Another common use for a stylesheet parameter is to pass in data that a servlet generates dynamically, such as a unique ID for session tracking.
From JAXP, pass this parameter via the Transformer instance. The code is simple enough:
javax.xml.transform.Transformer trans =
transFact.newTransformer(xsltSource);
trans.setParameter("image_dir", "graphics");
You can set as many parameters as you like, and these parameters
will be saved and reused for every transformation you make with this Transformer instance. If you wish to remove a parameter,
you must call clearParameters( ), which clears all
parameters for this Transformer instance.
Parameters work similarly to a java.util.Map; if
you set the same parameter twice, the second value overwrites the first value.
Another use for the Transformer class
is to get and set output properties through one of the following methods:
void setOutputProperties(java.util.Properties props)
void setOutputProperty(String name, String value)
java.util.Properties getOutputProperties( )
String getOutputProperty(String name)
As you can see, properties are specified as name/value pairs of
Strings and can be set and retrieved individually or as a group. Unlike
stylesheet parameters, you can un-set an individual property by simply passing
in null for the value. The permitted property names
are defined in the javax.xml.transform.OutputKeys
class and are explained in Table 5-1.
| Table 5-1: Constants defined in javax.xml.transform.OutputKeys | |
|
Constant |
Meaning |
|
|
Specifies a whitespace-separated list of element names whose content should be output as CDATA sections. See the XSLT specification from the W3C for examples. |
|
Only used if |
|
|
Instructs the processor to output a document-type
declaration. For example: |
|
|
Specifies the character encoding of the result tree, such as UTF-8 or UTF-16. |
|
|
Specifies whether or not whitespace may be added to
the result tree, making the output more readable. Acceptable values are
|
|
|
The MIME type of the result tree. |
|
|
The output method, either |
|
|
Acceptable values are |
|
|
Acceptable values are |
|
|
Specifies the version of the output method, typically
|
It is no coincidence that these output properties are the same
as the properties you can set on the <xsl:output> element in your stylesheets. For
example:
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
Using JAXP, you can either specify additional output properties or override those set in the stylesheet. To change the encoding, write this code:
// this will take precedence over any encoding specified in the stylesheet
trans.setOutputProperty(OutputKeys.ENCODING, "UTF-16");
Keep in mind that this will, in addition to adding encoding="UTF-16" to the XML declaration, actually cause the processor to use that encoding in the result tree. For a value of UTF-16, this means that 16-bit Unicode characters will be generated, so you may have trouble viewing the result tree in many ASCII-only
text editors.
JAXP XSLT Design
Now that we have seen some example code and have begun our
exploration of the Transformer class, let's step
back and look at the overall design of the XSLT plugability layer. JAXP
support for XSLT is broken down into the packages listed in Table
5-2
| Table 5-2: JAXP transformation packages | |
|
Package |
Description |
|
|
Defines a general-purpose API for XML transformations
without any dependencies on SAX or DOM. The |
|
|
Defines how transformations can be performed using
DOM. Provides implementations of |
|
|
Supports SAX2 transformations. Defines SAX versions of
|
|
|
Defines I/O stream implementations of |
The heart of JAXP XSLT support lies in the javax.xml.transform package, which lays out the mechanics
and overall process for any transformation that is performed. This package
mostly consists of interfaces and abstract classes, except for OutputKeys and a few exception and error classes. Figure 5-2 presents a UML class diagram that shows all of the pieces in this important package.
|
As you can see, this is a small package, indicative of the fact
that JAXP is merely a wrapper around the tools that actually perform
transformations. The entry point is TransformerFactory, which creates instances of Transformer, as we have already seen, as well as
instances of the Templates abstract class. A Templates object represents a compiled stylesheet and
will be covered in detail later in this chapter.
|
The exact definition of a "compiled" stylesheet is vague. XSLT processors are free to optimize cached stylesheets however they see fit. |
Templates object can be used over and over by many threads without reparsing the XSLT file.
The URIResolver is responsible for
resolving URIs found within stylesheets and is generally something you will
not need to deal with directly. It is used when a stylesheet imports or
includes another document, and the processor needs to figure out where to look
for that document. For example:
<xsl:import href="commonFooter.xslt"/>
ErrorListener, as you may guess, is
an interface that allows your code to register as a listener for error
conditions. This interface defines the following three methods:
void error(TransformerException ex)
void fatalError(TransformerException ex)
void warning(TransformerException ex)
The TransformerException has the
ability to wrap around another Exception or Throwable object and may return an instance of the SourceLocator class. If the underlying XSLT implementation does not provide a SourceLocator,
null is returned. The SourceLocator interface defines methods to locate where a TransformerException originated. In the case of
error(...) and warning(...), the XSLT processor is required to continue
processing the document until the end. For fatalError(...), on the other hand, the XSLT processor is
not required to continue. If you do not register an ErrorListener object, then all errors, fatal errors, and
warnings are normally written to System.err.
TransformerFactoryConfigurationError
and TransformerConfigurationException round out the
error-handling APIs for JAXP, indicating problems configuring the underlying
XSLT processor implementation. The TransformerFactoryConfigurationError class is generally
used when the implementation class cannot be found on the CLASSPATH or cannot
be instantiated at all. TransformerConfigurationException simply indicates a
"serious configuration error" according to its documentation.
