The
process of outputting a JDOM Document
object is
even simpler than the process of creating one. The
org.jdom.output
package provides helper and utility
classes for outputting a Document
to various
sources. No interface is provided to define required behavior, as
output of a Document
can be used in a variety of
ways, from something as simple as writing to a file to something as
complex as triggering events for another application component to
use.
The most common use for XML data within a
JDOM Document
is to output that data as XML to a
file or another application component, using an OutputStream
. Of
course, this stream may wrap a console’s output, a file, a URL,
or any other construct that can receive data. This task is handled in
JDOM by the
org.jdom.output.XMLOutputter
class. This class provides the following
constructors and output method:
public class XMLOutputter { // Accept defaults: 2 space indent and new line feeds on public XMLOutputter( ); // Specify indent, accept default for new line feeds (on) public XMLOutputter(String indent); // Specify the indention to use and if new line feeds should be used public XMLOutputter(String indent, boolean newlines); // Output a JDOM Document to a stream public void output(Document doc, OutputStream out)throws IOException; }
When instantiated with the default constructor, this results in a
“pretty printing” of the JDOM
Document
; other options can be supplied for more
compact output (such as turning off new lines and removing
indentation, resulting in the smallest file possible). The following
example shows the
SAXTest
class we looked at earlier, revised to
print the document to the standard output:
import java.io.File;import java.io.IOException;
import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.input.Builder; import org.jdom.input.SAXBuilder;import org.jdom.output.XMLOutputter;
public class SAXTest { public static void main(String[] args) { if (args.length != 1) { System.out.println("Usage: SAXTest [filename to parse]"); return; } try { // Request document building without validation Builder builder = new SAXBuilder(false); Document doc = builder.build(new File(args[0]));printDocument(doc);
} catch (JDOMException e) { if (e.getRootCause( ) != null) { e.getRootCause().printStackTrace( ); } e.printStackTrace( );} catch (Exception e) {
e.printStackTrace( );
}
}public static void printDocument(Document doc) throws IOException {
XMLOutputter fmt = new XMLOutputter( );
fmt.output(doc, System.out);
}
}
Notice that in our methods that build JDOM
Document
objects with
SAXBuilder
and DOMBuilder
, we
didn’t perform any data massaging or manipulation after
building; a built Document
is immediately ready
for output, making reading and writing XML (possibly from one source
to another source) extremely easy.
We have already discussed applications of JDOM even when the original
XML is available only as a pre-built DOM tree; the
DOMBuilder
can convert the DOM tree to the much
lighter-weight JDOM Document
object, and the JDOM
API can be used to manipulate the XML data. In the same manner, JDOM
can communicate with other applications that expect
SAX events as input. The
org.jdom.SAXOutputter
class provides the ability to fire off
SAX events from a supplied JDOM
Document
object. This provides a complete
isolation level between application components, allowing you to use
JDOM while still interacting with applications that don’t use
JDOM (or just haven’t caught up yet!). Additionally, a
DOMOutputter
class is being developed to perform the
same type of task, converting a JDOM Document
object into a DOM tree to pass to other application components. Both
of these classes should be complete by the publication of this book,
so visit http://www.jdom.org to
obtain these updates, as well as the latest version of the JDOM
implementation classes.
More important than these two specific classes is the flexibility
they indicate: rather than being tied to a specific format, JDOM
seeks to allow input and output from any type of input source and to
any type of output source. An ApacheOutputter
class, for example, could be created to output a JDOM
Document
created with
ApacheBuilder
back into an Apache HTTP
configuration file format. The output formats can be as varied as the
input formats, as JDOM provides only an object model, rather than a
specific XML model.
As a more complete example of using JDOM,
Example 8.5 is a JDOM “test suite” that
builds a JDOM
Document
object from scratch, using
both SAXBuilder
and DOMBuilder
.
Example 8-5. JDOM Test Suite
import java.io.File; import java.io.IOException; import java.io.OutputStream; import org.jdom.Attribute; import org.jdom.Comment; import org.jdom.DocType; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.Namespace; import org.jdom.ProcessingInstruction; import org.jdom.input.Builder; import org.jdom.input.DOMBuilder; import org.jdom.input.SAXBuilder; import org.jdom.output.XMLOutputter; /** * <p> * Demonstrate building JDOM Documents from scratch and existing XML * data sources. * </p> * * @version 1.0 */ public class JDOMTest { public JDOMTest( ) { } /** * <p> * Build a JDOM <code>Document</code> from scratch * </p> * * @param out <code>OutputStream</code> to write created XML to * @throws <code>IOException</code> when output errors occur. */ public void newDocument(OutputStream out) throws IOException, JDOMException { Namespace ns = Namespace.getNamespace("linux", "http://www.linux.org"); Document doc = new Document(new Element("config", ns)) .setDocType(new DocType("linux:config", "DTD/linux.dtd")) .addProcessingInstruction("cocoon-process", "type="xsp"") .addProcessingInstruction( new ProcessingInstruction("cocoon-process", "type="xslt"")); doc.getRootElement( ) .addAttribute("kernel", "2.2.14") // easy way .addAttribute( new Attribute("dist", "RedHat 6.1")) // hard way .addChild(new Element("gui", ns) .setContent("No Window Manager Installed")) .addChild(new Comment("Sound Card Configuration")) .addChild(new Element("sound") .addChild(new Comment("Sound Blaster Card")) .addChild(new Element("card") .addChild(new Element("name") .setContent("Sound Blaster Platinum"))) ); XMLOutputter fmt = new XMLOutputter( ); fmt.output(doc, out); } public void domDocument(File file, OutputStream out) throws IOException, JDOMException { Builder builder = new DOMBuilder(true); Document doc = builder.build(file); XMLOutputter fmt = new XMLOutputter( ); fmt.output(doc, out); } public void saxDocument(File file, OutputStream out) throws IOException, JDOMException { Builder builder = new SAXBuilder(true); Document doc = builder.build(file); XMLOutputter fmt = new XMLOutputter( ); fmt.output(doc, out); } /** * <p> * Static entry point for JDOM testing. * </p> */ public static void main(String[] args) { if (args.length != 1) { System.out.println("Usage: JDOMTest [filename to parse]"); System.exit(-1); } try { JDOMTest test = new JDOMTest( ); System.out.println( " ----------------------------------------"); System.out.println( "Testing creating Document from scratch ..."); System.out.println( "---------------------------------------- "); test.newDocument(System.out); System.out.println( " ----------------------------------------"); System.out.println( "Testing reading Document using DOM ..."); System.out.println( "---------------------------------------- "); test.domDocument(new File(args[0]), System.out); System.out.println( " ----------------------------------------"); System.out.println( "Testing reading Document using SAX ..."); System.out.println( "---------------------------------------- "); test.saxDocument(new File(args[0]), System.out); System.out.println( " ----------------------------------------"); System.out.println( "Tests complete. Successful build in place."); } catch (Exception e) { e.printStackTrace( ); if (e instanceof JDOMException) { System.out.println(((JDOMException)e).getRootCause( ) .getMessage( )); } else { System.out.println(e.getMessage( )); } } } }
Compile the JDOMTest
class, and let’s take a look at its
output. Supplying an XML file to the class, we can see the file
output twice, once built with SAX and once built with DOM, which
follows the new XML data created from scratch. Example 8.6 shows parts of this output.
Example 8-6. Output from JDOMTest Class
$ java JDOMText contents.xml ---------------------------------------- Testing creating tree from scratch ... ---------------------------------------- <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE linux:config SYSTEM "DTD/linux.dtd"> <?cocoon-process type="xsp"?> <?cocoon-process type="xslt"?> <linux:config xmlns:linux="http://www.linux.org" kernel="2.2.14" dist="RedHat 6.1"> <linux:gui>No Window Manager Installed</linux:gui> <!--Sound Card Configuration--> <sound> <!--Sound Blaster Card--> <card> <name>Sound Blaster Platinum</name> </card> </sound> </linux:config> ---------------------------------------- Testing reading tree using DOM ... ---------------------------------------- <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE JavaXML:Book SYSTEM "DTDJavaXML.dtd"> <?xml-stylesheet href="XSLJavaXML.html.xsl" type="text/xsl"?> <?xml-stylesheet href="XSLJavaXML.wml.xsl" type="text/xsl" media="wap"?> <?cocoon-process type="xslt"?> <!-- Java and XML --> <JavaXML:Book xmlns:JavaXML="http://www.oreilly.com/catalog/javaxml/"> <JavaXML:Title>Java and XML</JavaXML:Title> <JavaXML:Contents> <JavaXML:Chapter focus="XML"> <JavaXML:Heading>Introduction</JavaXML:Heading> <JavaXML:Topic subSections="7">What Is It?</JavaXML:Topic> ... ---------------------------------------- Testing reading tree using SAX ... ---------------------------------------- <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE JavaXML:Book SYSTEM "DTDJavaXML.dtd"> <?xml-stylesheet href="XSLJavaXML.html.xsl" type="text/xsl"?> <?xml-stylesheet href="XSLJavaXML.wml.xsl" type="text/xsl" media="wap"?> <?cocoon-process type="xslt"?> <!-- Java and XML --> <JavaXML:Book xmlns:JavaXML="http://www.oreilly.com/catalog/javaxml/"> <JavaXML:Title>Java and XML</JavaXML:Title> <JavaXML:Contents> <JavaXML:Chapter focus="XML"> <JavaXML:Heading>Introduction</JavaXML:Heading> ...
This output was the result of running JDOMTest
with the contents.xml
document we have been
working with through the various chapters. The
JavaXML:References
element (and its children) is
commented out, as our DTD does not allow those elements in the
document. Leaving those elements in results in the following error
message (when validation is requested in creating a
SAXBuilder
or DOMBuilder
instance):
org.jdom.JDOMException: Error on line 59 of XML document: Element type "JavaXML:References" must be declared. at org.jdom.input.DOMBuilder.build(DOMBuilder.java:121) at org.jdom.input.AbstractBuilder.build(AbstractBuilder.java:58) at JDOMTest.domDocument(JDOMTest.java:46) at JDOMTest.main(JDOMTest.java:79) Error on line 59 of XML document: Element type "JavaXML:References" must be declared.
One of the key features of JDOM is this error testing; this provides detailed
information about the location within the XML input where errors
occurred, making validation and well-formedness checking simple.
Because input and output of an XML source takes only four lines of
code (as shown in the domDocument( )
and
saxDocument( )
methods), JDOM can be used to
provide a means to ensure your XML documents are well-formed and
valid.
For those of you paying close attention, you may have noticed something we did not have to worry about in the code above: validation and namespaces cooperating! Because JDOM handles namespaces internally (rather than depending on DOM Level 2 or SAX 2.0 to supply namespace information), it can perform validation while still providing namespace support. In fact, JDOM actually turns namespace-awareness off in SAXBuilder
and DOMBuilder
! Not only does this allow validation to occur, but it actually speeds up processing of XML documents.
As a final look at JDOM, we revisit the
SAXParserDemo
and DOMParserDemo
from Chapter 3 and Chapter 7 briefly. Both of these programs printed out
XML documents from an input file; while the
SAXParserDemo
provided more of a lifecycle view of
the SAX parsing process, DOMParserDemo
was
essentially a “pretty-printer” class, outputting the DOM
tree in human-readable format. Both classes allowed a look at an XML
document; Example 8.7 shows the source for
com.oreilly.xml.PrettyPrinter
, a utility class
that performs this same task using JDOM.
Example 8-7. The com.oreilly.xml.PrettyPrinter Utility Class
package com.oreilly.xml; import java.io.File; import org.jdom.Document; import org.jdom.input.Builder; import org.jdom.input.SAXBuilder; import org.jdom.output.XMLOutputter; /** * <b><code>PrettyPrinter</code></b> will output the XML document at a * given URI * * @author * <a href="mailto:[email protected]">Brett McLaughlin</a> * @author <a href="mailto:[email protected]">Jason Hunter</a> * @version 1.0 */ public class PrettyPrinter { /** * <p> * Pretty prints a given XML URI * </p> */ public static void main(String[] args) { if (args.length != 1) { System.out.println("Usage: " + "java com.oreilly.xml.PrettyPrinter [XML_URI]"); return; } String filename = args[0]; try { // Build the Document with SAX and Xerces, no validation Builder builder = new SAXBuilder( ); // Create the document (without validation) Document doc = builder.build(new File(filename)); // Output the document, use standard formatter XMLOutputter fmt = new XMLOutputter( ); fmt.output(doc, System.out); } catch (Exception e) { e.printStackTrace( ); } } }
At this point, we have taken a bit of a whirlwind tour through JDOM,
and only seen a glimpse of its full functionality. The complete API
is documented in Appendix A, and includes all JDOM
classes and interfaces, as well as the methods available for each.
The support packages for JDOM, org.jdom.adapters
,
org.jdom.input
, and
org.jdom.output
, are also documented in Appendix A. To continue to illustrate how JDOM is used
(as we do with SAX and DOM), we will use JDOM in the examples
throughout the rest of the book. Additionally, we compare JDOM to SAX
and DOM in each example, ensuring that you can perform tasks using
all three APIs when needed. Ultimately, you can decide when each API
is useful, and code accordingly. Finally, the most current version of
JDOM and the corresponding Javadoc are available
online at
http://www.jdom.org and http://www.newInstance.com.
3.144.97.216