Writing Out a DOM as an XML File



Writing Out a DOM as an XML File

Once you have constructed a DOM, either by parsing an XML file or building it programmatically, you frequently want to save it as XML. This section shows you how to do that using the XSLT transform package.

Using that package, you'll create a transformer object to wire a DomSource to a StreamResult. You'll then invoke the transformer's transform() method to do the job!

1 Reading the XML

The first step is to create a DOM in memory by parsing an XML file. By now, you should be getting pretty comfortable with the process!

Note

The code discussed in this section is in TransformationApp01.java.


The code below provides a basic template to start from. (It should be familiar. It's basically the same code you wrote at the start of the DOM tutorial. If you saved it then, that version should be pretty much the equivalent of what you see below.)


import javax.xml.parsers.DocumentBuilder; 
import javax.xml.parsers.DocumentBuilderFactory; 
import javax.xml.parsers.FactoryConfigurationError; 
import javax.xml.parsers.ParserConfigurationException; 

import org.xml.sax.SAXException; 
import org.xml.sax.SAXParseException; 
import org.w3c.dom.Document; 
import org.w3c.dom.DOMException; 
import java.io.*; 
public class TransformationApp 
{
    static Document document; 
    public static void main(String argv[]) 
    {
        if (argv.length != 1) {
            System.err.println ("Usage: java TransformationApp 
filename"); 
            System.exit (1); 
        } 
        DocumentBuilderFactory factory = 
            DocumentBuilderFactory.newInstance(); 
        //factory.setNamespaceAware(true); 
        //factory.setValidating(true); 
         try {
            File f = new File(argv[0]); 
            DocumentBuilder builder = factory.newDocumentBuilder(); 
            document = builder.parse(f); 
         } catch (SAXException sxe) {
            // Error generated by this application 
            // (or a parser-initialization error) 
            Exception  x = sxe; 
            if (sxe.getException() != null) 
                x = sxe.getException(); 
            x.printStackTrace(); 
         } catch (ParserConfigurationException pce) {
            // Parser with specified options can't be built 
            pce.printStackTrace(); 
         } catch (IOException ioe) {
            // I/O error 
            ioe.printStackTrace(); 
        } 
} // main 
}

2 Creating a Transformer

The next step is to create a transformer you can use to transmit the XML to System.out.

Note

The code discussed in this section is in TransformationApp02.java. The file it runs on is slideSample01.xml. (The browsable version is slideSample01-xml.html.) The output is in TransformationLog02.


Start by adding the import statements highlighted below:


import javax.xml.transform.Transformer; 
import javax.xml.transform.TransformerFactory; 
import javax.xml.transform.TransformerException; 
import javax.xml.transform.TransformerConfigurationException; 
import javax.xml.transform.dom.DOMSource; 

import javax.xml.transform.stream.StreamResult; 

import java.io.*;

Here, you've added a series of classes that should be now be forming a standard pattern: an entity (Transformer), the factory to create it (TransformerFactory), and the exceptions that can be generated by each. Since a transformation always has a source and a result, you then imported the classes necessary to use a DOM as a source (DomSource), and an output stream for the result (StreamResult).

Next, add the code to carry out the transformation:


try {
    File f = new File(argv[0]); 
    DocumentBuilder builder = factory.newDocumentBuilder(); 
    document = builder.parse(f); 

     // Use a Transformer for output 
    TransformerFactory tFactory = 
        TransformerFactory.newInstance(); 
    Transformer transformer = tFactory.newTransformer(); 

     DOMSource source = new DOMSource(document); 
     StreamResult result = new StreamResult(System.out); 
    transformer.transform(source, result);

Here, you created a transformer object, used the DOM to construct a source object, and used System.out to construct a result object. You then told the transformer to operate on the source object and output to the result object.

Note

In this case, the "transformer" isn't actually changing anything. In XSLT terminology, you are using the identity transform, which means that the "transformation" generates a copy of the source, unchanged.


Finally, add the code highlighted below to catch the new errors that can be generated:


} catch (TransformerConfigurationException tce) { 
    // Error generated by the parser 
    System.out.println ("* Transformer Factory error"); 
    System.out.println("   " + tce.getMessage() ); 
     // Use the contained exception, if any 
    Throwable x = tce; 
    if (tce.getException() != null) 
        x = tce.getException(); 
    x.printStackTrace(); 

} catch (TransformerException te) { 
    // Error generated by the parser 
    System.out.println ("* Transformation error"); 
    System.out.println("   " + te.getMessage() ); 

    // Use the contained exception, if any 
    Throwable x = te; 
    if (te.getException() != null) 
        x = te.getException(); 
    x.printStackTrace(); 

} catch (SAXException sxe) {
    ...

Note

TransformerExceptions are thrown by the transformer object.

TransformerConfigurationExceptions are thrown by the factory.


Addendum:

Astute reader Malcolm Gorman points out that, as it is currently written, the

transformation app won't preserve the XML document's DOCTYPE setting. He proposes the following code to remedy the omission:


String systemValue = (new 
File(document.getDoctype().getSystemId())).getName(); 
transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, 
    systemValue);

3 Writing the XML

For instructions on how to compile and run the program, see Compiling and Running the Program (page 91) from the SAX tutorial. (Substitute "TransformationApp" for "Echo" as the name of the program.). When you run the program on slideSample01.xml, following is the output you see.


<?xml version="1.0" encoding="UTF-8"?> 
<!--  A SAMPLE set of slides  --> 
<slideshow title="Sample Slide Show" date="Date of publication" 
author="Yours Truly"> 
      <!-- TITLE SLIDE --> 
      <slide type="all"> 
         <title>Wake up to WonderWidgets!</title> 
      </slide> 
      <!-- OVERVIEW --> 
      <slide type="all"> 
          <title>Overview</title> 
          <item>Why 
        <em>WonderWidgets</em> are great 
     </item> 
          <item /> 
          <item>Who 
      <em>buys</em> WonderWidgets 
    </item> 
      </slide> 
</slideshow>

Note

See Additional Information (page 154) to find out more about configuring the factory and handling validation errors.


4 Writing Out a Subtree of the DOM

It is also possible to operate on a subtree of a DOM. In this section of the tutorial, you'll experiment with that option.

Note

The code discussed in this section is in TransformationApp03.java. The output is in TransformationLog03.


The only difference in the process is that now you will create a DOMSourceusing a node in the DOM, rather than the entire DOM. The first step will be to import the classes you need to get the node you want. Add the code highlighted below to do that:


import org.w3c.dom.DOMException; 
import org.w3c.dom.Node; 
import org.w3c.dom.NodeList;

The next step is to find a good node for the experiment. Add the code highlighted below to select the first <slide> element:


try {
    File f = new File(argv[0]); 
    DocumentBuilder builder = factory.newDocumentBuilder(); 
    document = builder.parse(f); 

    // Get the first <slide> element in the DOM 
    NodeList list = document.getElementsByTagName("slide"); 
    Node node = list.item(0);

Finally, make the changes shown below to construct a source object that consists of the subtree rooted at that node:


DOMSource source = new DOMSource(document); 
DOMSource source = new DOMSource(node); 
StreamResult result = new StreamResult(System.out); 
transformer.transform(source, result);

Now run the app. Your output should look like this:


    <?xml version="1.0" encoding="UTF-8"?> 
<slide type="all"> 
        <title>Wake up to WonderWidgets!</title> 
    </slide>
Clean Up

Because it will be easiest to do now, make the changes shown below to back out the additions you made in this section. (TransformationApp04.java contains these changes.)


Import org.w3c.dom.DOMException; 
import org.w3c.dom.Node; 
import org.w3c.dom.NodeList; 
... 
    try {
        ... 
        // Get the first <slide> element in the DOM 
        NodeList list = document.getElementsByTagName("slide"); 
        Node node = list.item(0); 
        ... 
        DOMSource source = new DOMSource(node); 
        StreamResult result = new StreamResult(System.out); 
        transformer.transform(source, result);

5 Summary

At this point, you've seen how to use a transformer to write out a DOM, and how to use a subtree of a DOM as the source object in a transformation. In the next section, you'll see how to use a transformer to create XML from any data structure you are capable of parsing.