See also: Transform Features.
| Unless otherwise specified, the usage discussed in this section refers to
the Xalan-Java Interpretive processor. See Getting Started Using
XSLTC for information on using the Xalan-Java Compiling processor. |
| | | | 3. Use the Transformer to perform a transformation | | | | |
| |
Use the Transformer transform(Source xmlSource, Result transformResult) method to transform the XML Source and place the transformation output in a Result object.
Just as with the stylesheet, you can supply the XML Source in the form of a StreamSource, DOMSource, or SAXSource. Likewise, the Result may be a StreamResult, DOMResult, or SAXResult.
For each node in the XML source, the Transformer uses the transformation instructions in the Templates object to determine which template to apply: one of the templates in the Templates object, a default template rule as specified in the XSLT spec, or none.
|
| | | | Working with embedded stylesheets | | | | |
| |
An XML Source may include an xml-stylesheet processing instruction which identifies the stylesheet to be used to process the document. As indicated by the processing instruction href attribute, the stylesheet itself may be embedded in the XML document or located elsewhere.
Suppose you have an XML document (foo.xml) with the following xml-stylesheet processing instruction:
<?xml-stylesheet type="text/xml" href="foo.xsl"?>
The following fragment uses this instruction to locate the stylesheet (foo.xsl in the same directory as foo.xml) and create a Templates object. Note the use of the TransformerFactory getAssociatedStylesheet() in step 2a.
| An XML document may include more than one xml-stylesheet processing instruction, hence the support for working with multiple stylesheets. If more than one stylesheet is returned, the other stylesheets are imported into the first stylesheet. |
| | | | // 1. Instantiate the TransformerFactory.
javax.xml.transform.TransformerFactory tFactory =
javax.xml.transform.TransformerFactory.newInstance();
// 2a. Get the stylesheet from the XML source.
String media = null , title = null, charset = null;
javax.xml.transform.Source stylesheet = tFactory.getAssociatedStylesheet
(new StreamSource("foo.xml"), media, title, charset);
// 2b. Process the stylesheet and generate a Transformer.
Transformer transformer = tFactory.newTransformer(stylesheet);
// 3. Use the Transformer to perform the transformation and send the
// the output to a Result object.
transformer.transform
(new javax.xml.transform.stream.StreamSource("foo.xml"),
new StreamResult (new java.io.FileOutputStream("foo.out"))); | | | | |
For a sample that uses this technique, see UseStylesheetPI.
You can also instruct the command-line utility to use stylesheet processing
instructions:
- Include the
-in flag with an XML source that contains a stylesheet processing instruction.
- Do not include the
-xsl flag.
|
| |
In some cases, you may want to "transform" a DOM tree into a stream, which the XML community calls serialization.
JAXP 1.3 and the Xalan-Java Transformer implementation provide direct
support for this operation. Simply use the TransformerFactory newTransformer() method (no arguments) to create a Transformer
that you can use to "copy" a DOMSource to a StreamResult. For examples, see Examples.exampleDOM2DOM(),
Examples.exampleSerializeNode(), and Examples.exampleAsSerializer() in the trax (JAXP transform) sample.
|
| | | | Explicitly working with SAX | | | | |
| |
Xalan-Java uses the SAX event model to process stylesheets, to parse XML input documents, and to produce output. For each of these operations, an XMLReader reads input, firing parse events, and a ContentHandler listens to the XMLReader and executes parse event methods.
When you use the basic procedure described above for performing transformations, Xalan-Java takes care of many of the SAX details under the covers. You are free to make these details explicit, which simply means that you can intervene in the procedure to accommodate the precise environment in which your application operates.
Suppose, for example, you are using a custom XMLReader (perhaps for doing more than just parsing static XML documents) to generate Xalan-Java SAX parse events. You might even have a custom reader for producing/processing stylesheets. You can cast the TransformerFactory to a SAXTransformerFactory, which provides access to a TransformerHandler, which you can set as the ContentHandler for this reader.
The following example explicitly sets up the XMLReader and ContentHandlers, and replicates the basic steps described above.
| | | | // Instantiate a TransformerFactory.
javax.xml.transform.TransformerFactory tFactory =
javax.xml.transform.TransformerFactory.newInstance();
// Verify that the TransformerFactory implementation you are using
// supports SAX input and output (Xalan-Java does!).
if (tFactory.getFeature(javax.xml.transform.sax.SAXSource.FEATURE) &&
tFactory.getFeature(javax.xml.transform.sax.SAXResult.FEATURE))
{
// Cast the TransformerFactory to SAXTransformerFactory.
javax.xml.transform.sax.SAXTransformerFactory saxTFactory =
((javax.xml.transform.sax.SAXTransformerFactory) tFactory);
// Create a Templates ContentHandler to handle parsing of the
// stylesheet.
javax.xml.transform.sax.TemplatesHandler templatesHandler =
saxTFactory.newTemplatesHandler();
// Create an XMLReader and set its ContentHandler.
org.xml.sax.XMLReader reader =
org.xml.sax.helpers.XMLReaderFactory.createXMLReader();
reader.setContentHandler(templatesHandler);
// Parse the stylesheet.
reader.parse("foo.xsl");
// Get the Templates object (generated during the parsing of the stylesheet)
// from the TemplatesHandler.
javax.xml.transform.Templates templates =
templatesHandler.getTemplates();
// Create a Transformer ContentHandler to handle parsing of
// the XML Source.
javax.xml.transform.sax.TransformerHandler transformerHandler
= saxTFactory.newTransformerHandler(templates);
// Reset the XMLReader's ContentHandler to the TransformerHandler.
reader.setContentHandler(transformerHandler);
// Set the ContentHandler to also function as a LexicalHandler, which
// can process "lexical" events (such as comments and CDATA).
reader.setProperty("http://xml.org/sax/properties/lexical-handler",
transformerHandler);
// Set up a Serializer to serialize the Result to a file.
org.apache.xml.serializer.Serializer serializer =
org.apache.xml.serializer.SerializerFactory.getSerializer
(org.apache.xml.serializer.OutputPropertiesFactory.getDefaultMethodProperties
("xml"));
serializer.setOutputStream(new java.io.FileOutputStream("foo.out"));
// The Serializer functions as a SAX ContentHandler.
javax.xml.transform.Result result =
new javax.xml.transform.sax.SAXResult(serializer.asContentHandler());
transformerHandler.setResult(result);
// Parse the XML input document.
reader.parse("foo.xml"); | | | | |
| If you want to perform multiple transformations with the same Templates object and a TransformerHandler, you must create a new
TransformerHandler for each transformation. The Xalan-Java implementation of TransformerHandler
(TransformerHandlerImpl fails to respond
to events after the first endDocument event occurs. |
|
| | | | Processing and producing DOM trees | | | | |
| |
In some cases, the input and/or desired output for a transformation may be a DOM tree object. The javax.xml.transform.DOM package provides DOMSource and a DOMResult, either or both of which you can use when you perform a transformation.
In some cases, your application provides input in the form of a DOM tree, which accelerates the transformation process, since the input has in effect already been processed. To produce DOM input from a stream, you can use a DocumentBuilderFactory to produce a DocumentBuilder with which you can parse the XML input into a DOM Document, as illustrated below.
| | | | // Instantiate a DocumentBuilderFactory.
javax.xml.parsers.DocumentBuilderFactory dfactory =
javax.xml.parsers.DocumentBuilderFactory.newInstance();
// Use the DocumentBuilderFactory to provide access to a DocumentBuilder.
javax.xml.parsers.DocumentBuilder dBuilder = dfactory.newDocumentBuilder();
// Use the DocumentBuilder to parse the XML input.
org.w3c.dom.Document inDoc = dBuilder.parse("foo.xml"); | | | | |
To produce DOM output, simply use a Transformer to transform to a DOMResult object.
| | | | // Generate a Transformer.
javax.xml.transform.Transformer transformer = tFactory.newTransformer
(new javax.xml.transform.stream.StreamSource("foo.xsl"));
// Create an empy DOMResult object for the output.
javax.xml.transform.dom.DOMResult domResult =
new javax.xml.transform.dom.DOMResult();
// Perform the transformation.
transformer.transform(new javax.xml.transform.dom.DOMSource(inDoc),
domResult);
// Now you can get the output Node from the DOMResult.
org.w3c.dom.Node node = domResult.getNode(); | | | | |
| Create a new DOMResult object or use DOMResult.setNode() to assign a new container each time you want to perform a transformation
and place the output in a DOMResult object. |
The DOM2DOM illustrates both procedures, and serializes the DOMResult to System.out.
|
| | | | Working with XPath expressions | | | | |
| |
XSLT stylesheets use XPath expressions to select nodes, specify conditions, and generate text for the result tree. XPath provides an API that you can call directly. For example, you may want to evaluate an XPath expression programmatically and do your own processing without a stylesheet.
XPath is an independent entity, with clients other than XSLT processors (such as XPointer). Accordingly, Xalan-Java 2 has packaged XPath as a separate module (org.apache.xpath and its subpackages). The org.apache.xpath.XPathAPI class contains convenience methods that you can use to return single DOM Nodes, NodeIterators, and XObjects. Apart from their own functionality, these methods also provide a path into the lower-level XPath API that you may find useful.
JAXP 1.3 also provides an API for xpath expression evaluation in the javax.xml.xpath package. Users are
recommended to use the new JAXP 1.3 XPath API rather than the old Xalan-Java 2 specific XPath API.
For an example that uses the Xalan-Java 2 specific XPathAPI to execute XPath expressions against XML source files,
see ApplyXPath. For examples on how to use the new JAXP 1.3 XPath
API, see ApplyXPathJAXP and
XPathResolver.
|
| | | | Using the Xalan-Java applet wrapper | | | | |
| |
- Include XSLTProcessorApplet in an HTML client.
- Specify the XML source document and XSL stylesheet.
You can use the DocumentURL and StyleURL PARAM tags or the setdocumentURL() and setStyleURL() methods. If the XML document contains a stylesheet Processing Instruction (PI), you do not need to specify an XSL stylesheet.
- Call the transformToHtml() or getHtmlText() method, which performs the transformation and returns the new document as a String.
| The transformToHTML() method takes arguments for the XML source document and XSL stylesheet. The getHtmlText() method takes no arguments: it uses property or parameter settings, as in the example below. |
For an example, see the AppletXMLtoHTML sample applet. The <applet> tag is in samples/AppletXMLtoHTML/client.html:
| | | | <applet
name="xslControl"
code="org.apache.xalan.client.XSLTProcessorApplet.class"
archive="../../xalan.jar,../../build/xalan.jar,../../serializer.jar,../../build/serializer.jar,../../lib/xml-apis.jar,../../lib/xercesImpl.jar"
height="0"
width"0">
<param name="documentURL" value="xalanApplets.xml"/>
<param name="styleURL" value="s1ToHTML.xsl"/>
</applet> | | | | |
When the user clicks the Transform button, the HTML client calls the getHtmlText() method, and puts the returned HTML text in a frame for the user to view.
For samples, see AppletXMLtoHTML.
| |
The JAXP strategy of reading system properties
generates SecurityExceptions when you attempt to run Xalan-Java applets in the Netscape Communicator 4.7.
Stuart Connell
<Stuart.Connell@compuware.com> reports that the Xalan-Java applet wrapper does work in Netscape Communicator 6,
provided that you avoid calls to the AppletContext showStatus() method. In other words, you can remove the showStatus() calls
from org.apache.xalan.client.XSLTProcessorApplet, and run Xalan-Java applets from Netscape Communicator 6. This appears to be a
Netscape bug, which hopefully will be fixed soon. For more information, see
Bugzilla bug 3231.
|
|
| | | | Using Xalan-Java in a servlet | | | | |
| |
You can set up a servlet to use Xalan-Java to respond to requests for XML documents by transforming those documents into HTML and serving them to web browsers. To respond to HTTP GET requests, all you need to do is overwrite the HttpServlet doGet() method with a procedure that instantiates a Transformer and uses it to perform a transformation. As the following example shows, you can generate a ResultStream that a PrintWriter writes to the HttpResponse OutputStream, returning the transformation output to the web browser.
| | | |
public class SampleXSLTServlet extends javax.servlet.http.HttpServlet {
public final static String FS = System.getProperty("file.separator");
// Respond to HTTP GET requests from browsers.
public void doGet (javax.servlet.http.HttpServletRequest request,
javax.servlet.http.HttpServletResponse response)
throws javax.servlet.ServletException, java.io.IOException
{
// Set content type for HTML.
response.setContentType("text/html; charset=UTF-8");
// Output goes to the response PrintWriter.
java.io.PrintWriter out = response.getWriter();
try
{
javax.xml.transform.TransformerFactory tFactory =
javax.xml.transform.TransformerFactory.newInstance();
//get the real path for xml and xsl files.
String ctx = getServletContext().getRealPath("") + FS;
// Get the XML input document and the stylesheet, both in the servlet
// engine document directory.
javax.xml.transform.Source xmlSource =
new javax.xml.transform.stream.StreamSource
(new java.net.URL("file", "", ctx+"foo.xml").openStream());
javax.xml.transform.Source xslSource =
new javax.xml.transform.stream.StreamSource
(new java.net.URL("file", "", ctx+"foo.xsl").openStream());
// Generate the transformer.
javax.xml.transform.Transformer transformer =
tFactory.newTransformer(xslSource);
// Perform the transformation, sending the output to the response.
transformer.transform(xmlSource,
new javax.xml.transform.stream.StreamResult(out));
}
// If an Exception occurs, return the error to the client.
catch (Exception e)
{
out.write(e.getMessage());
e.printStackTrace(out);
}
// Close the PrintWriter.
out.close();
}
} | | | | |
For a working sample, see SimpleXSLTServlet.
In the preceding example, the URLs for the XML document and XSL stylesheet are hardcoded in the servlet. You can also create a servlet that parses the request URL for input parameters specifying the XML document, XSL stylesheet, and any relevant stylesheet parameters. For samples, see UseStylesheetParamServlet and XSLTServletWithParams. For a more robust and complex sample that also employs a properties file to determine which stylesheet to use depending on the client browser/device, see ApplyXSLT.
|
| |
A given Templates object may be used repeatedly and even in multiple threads running concurrently for the transformation of XML input, but you should use the Templates object to instantiate a separate Transformer for each transformation you perform. The Templates object is an immutable runtime representation of the structure and content of a stylesheet (which may include and import multiple stylesheet sources). A Transformer, on the other hand, is a lightweight object that tracks state information during the transformation, and should only be used to perform a single transformation.
If you want to perform multiple transformations (sequentially or concurrently) with the same stylesheet instructions, do the following:
- Use the TransformerFactory newTemplates(Source xslSource) method to create a Templates object.
- For each transformation, use the Templates object newTransformer() method to create a Transformer, and use that Transformer's
transform(Source xmlSource, Result transformResult) method to perform the transformation.
For an example, see Examples.exampleUseTemplatesObj() in the trax sample.
|
|