 | Level: Intermediate Brett McLaughlin (brett@newInstance.com), Author/Editor, O'Reilly Media, Inc.
01 Mar 2001 In this tip, Brett McLaughlin tells how to avoid a common pitfall when working with XSLT and the JDOM API for XML developers working in Java. You'll learn how to take a JDOM document representation, transform it using the Apache Xalan processor, and obtain the resulting XML as another JDOM document. Transforming a document using XSLT is a common task, and JDOM makes the transformation go quite easily once you know how to avoid the missteps. The code demonstrates how to use JDOM with the new Apache Xalan 2 processor (for Java).
Being one of the co-creators of JDOM, I simply couldn't pass up the
chance to throw in a few JDOM tips in a series of XML tips and tricks.
This tip provides the answer to one of the most common questions I get
about JDOM: "How do I use JDOM and XSLT together?" People aren't sure how
to take a JDOM Document object and feed it into an XSLT processor.
The confusion often arises because most XSLT processors take either DOM
trees or SAX events as input streams. In other words, there is not one
obvious way to provide a JDOM Document as input in all cases.
So how do you interface JDOM with those processors?
The key to solving this problem is understanding the input and output
options. First determine the input formats that your XSLT processor accepts.
As I mentioned above, you'll usually be able to feed a DOM tree or I/O
stream into the processor. But which of those is the faster solution? You're
going to have to do a little digging to answer that question. (That's right,
I'm not going to give you a specific answer, but a method for figuring
it out.) Check out your processor's documentation, and even ask the vendor
for the particular format that is used internally.
Many processors currently use a DOM tree as the internal document representation.
For these processors, passing in a DOM tree is the best option because the processor
can use that structure immediately, without any internal conversion. Converting your JDOM Document to a stream (using XMLOutputter)
would waste time, as that stream is just going to be converted back into
a DOM tree. So always try to find the shortest path between JDOM and the
processor's internal representation. If you need to feed the processor
a DOM tree, use JDOM's DOMOutputter, and if you need to feed the
processor SAX, use SAXOutputter. In either case, the key is connecting
the correct output format for your JDOM Document with the best
solution for input to your XSLT processor.
To give you a more specific idea of how this works, let's look at using
the Apache Xalan processor and, in particular, the new Xalan 2 (the Java
version is actually called Xalan-J 2, but you get the idea). This open-source,
Java-based XSLT processor can work most efficiently with an I/O stream
input. While Xalan makes use of the DOM, it uses a fairly customized implementation
that allows Xalan to perform at peak speeds. For that reason, feeding in
a DOM tree does not end up not saving as much time as you would think.
Listing 1 takes a JDOM Document, converts it to an
output stream, and then feeds that stream into the Xalan XSLT processor.
Once the processor returns the transformed XML, that XML is converted back
into a JDOM Document for further processing. In other words, JDOM
in, JDOM out, and transformation occurs. Voila!
Listing 1. Using JDOM with Xalan-J 2
// JDOM imports
import org.jdom.Document;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;
// Xalan-J 2 imports
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
public Document transform(Document sourceDoc, File stylesheetFile) {
// Set up the XSLT stylesheet for use with Xalan-J 2
TransformerFactory transformerFactory =
TransformerFactory.newInstance();
Templates stylesheet = transformerFactory.newTemplates(
new StreamSource(stylesheetFile));
Transformer processor = stylesheet.newTransformer();
// Use I/O streams for source files
PipedInputStream sourceIn = new PipedInputStream();
PipedOutputStream sourceOut = new PipedOutputStream(sourceIn);
StreamSource source = new StreamSource(sourceIn);
// Use I/O streams for output files
PipedInputStream resultIn = new PipedInputStream();
PipedOutputStream resultOut = new PipedOutputStream(resultIn);
// Convert the output target for use in Xalan-J 2
StreamResult result = new StreamResult(resultOut);
// Get a means for output of the JDOM Document
XMLOutputter xmlOutputter = new XMLOutputter();
// Output to the I/O stream
xmlOutputter.output(sourceDoc, sourceOut);
sourceOut.close();
// Feed the resultant I/O stream into the XSLT processor
processor.transform(source, result);
resultOut.close();
// Convert the resultant transformed document back to JDOM
SAXBuilder builder = new SAXBuilder();
Document resultDoc = builder.build(resultIn);
return resultDoc;
}
|
By the way, thanks to Jan Hecking on the jdom-interest
mailing list for the code sample that I modified slightly in this tip.
Resources
About the author  | 
|  | Brett McLaughlin has worked in computers since the Logo days. (Remember the little triangle?) In recent years, he's become one of the most well-known authors and programmers in the Java and XML communities. He's worked for Nextel Communications, implementing complex enterprise systems; at Lutris Technologies, actually writing application servers; and most recently at O'Reilly Media, Inc., where he continues to write and edit books that matter. His most recent book,
Java 5.0 Tiger: A Developer's Notebook
, is the first book available on the newest version of Java technology, and his classic
Java and XML
remains one of the definitive works on using XML technologies in the Java language.
|
Rate this page
|  |