After 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 Xalan transform package.
Using that package, you will create a transformer object to wire a DOMSource to a StreamResult. You will then invoke the transformer's transform() method to write out the DOM as XML data.
The first step is to create a DOM in memory by parsing an XML file. By now, you should be getting comfortable with the process.
The code discussed in this section is in the file TransformationApp01.java. Download the XSLT examples and unzip them into the install-dir/jaxp-1_4_2-release-date/samples directory.
The following code provides a basic template to start from. It is basically the same code as was used at the start of the Document Object Model lesson.
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 TransformationApp01 { static Document document; public static void main(String argv[]) { if (argv.length != 1) { System.err.println ( "Usage: java TransformationApp01 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 (SAXParseException spe) { // Error generated by the parser System.out.println("\n** Parsing error" + ", line " + spe.getLineNumber() + ", uri " + spe.getSystemId()); System.out.println(" " + spe.getMessage() ); // Use the contained exception, if any Exception x = spe; if (spe.getException() != null) x = spe.getException(); x.printStackTrace(); } 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 cannot be built pce.printStackTrace(); } catch (IOException ioe) { // I/O error ioe.printStackTrace(); } } // main }
The next step is to create a transformer you can use to transmit the XML to System.out. To begin with, the following import statements are required.
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 add a series of classes that should now be forming a standard pattern: an entity (Transformer), the factory to create it (TransformerFactory), and the exceptions that can be generated by each. Because a transformation always has a source and a result, you then import 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 create a transformer object, use the DOM to construct a source object, and use System.out to construct a result object. You then tell the transformer to operate on the source object and output to the result object.
In this case, the "transformer" is not actually changing anything. In XSLT terminology, you are using the identity transform, which means that the "transformation" generates a copy of the source, unchanged.
You can specify a variety of output properties for transformer objects, as defined in the W3C specification at http://www.w3.org/TR/xslt#output. For example, to get indented output, you can invoke the following method:
% transformer.setOutputProperty(OutputKeys.INDENT, "yes");
Finally, the following highlighted code catches the new errors that can be generated:
} catch (TransformerConfigurationException tce) { System.out.println ("* Transformer Factory error"); System.out.println(" " + tce.getMessage() ); Throwable x = tce; if (tce.getException() != null) x = tce.getException(); x.printStackTrace(); } catch (TransformerException te) { System.out.println ("* Transformation error"); System.out.println(" " + te.getMessage() ); Throwable x = te; if (te.getException() != null) x = te.getException(); x.printStackTrace(); } catch (SAXParseException spe) { ...
Notes
TransformerExceptions are thrown by the transformer object.
TransformerConfigurationExceptions are thrown by the factory.
To preserve the XML document's DOCTYPE setting, it is also necessary to add the following code:
import javax.xml.transform.OutputKeys; ... if (document.getDoctype() != null){ String systemValue = (new File(document.getDoctype().getSystemId())).getName(); transformer.setOutputProperty( OutputKeys.DOCTYPE_SYSTEM, systemValue ); }
To find out more about configuring the factory and handling validation errors, see Reading XML Data into a DOM.
% cd install-dir/jaxp-1_4_2-release-date/samples.
% cd xslt
Type the following command:
% javac TransformationApp01.java
In the case below, TransformationApp01 is run on the file foo.xml, found in the xslt/data directory after you have unzipped the samples bundle.
% java TransformationApp01 data/foo.xml
You will see the following output:
<?xml version="1.0" encoding="UTF-8" standalone="no"?><doc> <name first="David" last="Marston"/> <name first="David" last="Bertoni"/> <name first="Donald" last="Leslie"/> <name first="Emily" last="Farmer"/> <name first="Joseph" last="Kesselman"/> <name first="Myriam" last="Midy"/> <name first="Paul" last="Dick"/> <name first="Stephen" last="Auriemma"/> <name first="Scott" last="Boag"/> <name first="Shane" last="Curcuru"/>
As mentioned in Creating a Transformer, this transformer has not actually changed anything, but rather has just performed the identity transform, to generate a copy of the source. A real transformation will be performed in Generating XML from an Arbitrary Data Structure.
It is also possible to operate on a subtree of a DOM. In this section, you will experiment with that option.
The code discussed in this section is in TranformationApp02.java. If you have not done so already, download the XSLT examples and unzip them into the install-dir/jaxp-1_4_2-release-date/samples directory.
The only difference in the process is that now you will create a DOMSource using a node in the DOM, rather than the entire DOM. The first step is to import the classes you need to get the node you want, as shown in the following highlighted code:
import org.w3c.dom.Document; 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. The following highlighted code selects the first <name> element.
try { File f = new File(argv[0]); DocumentBuilder builder = factory.newDocumentBuilder(); document = builder.parse(f); NodeList list = document.getElementsByTagName("name"); Node node = list.item(0);
In Creating a Transformer, the source object was constructed from the entire document by the following line of code
DOMSource source = new DOMSource(document);
However, the highlighted line of code below constructs a source object that consists of the subtree rooted at a particular node.
DOMSource source = new DOMSource(node); StreamResult result = new StreamResult(System.out); transformer.transform(source, result);
% cd install-dir/jaxp-1_4_2-release-date/samples.
cd xslt
Type the following command:
% javac xslt/TranformationApp02.java
In the case below, TranformationApp02 is run on the file foo.xml, found in the xslt/data directory after you have unzipped the samples bundle.
% java TranformationApp02 data/foo.xml
You will see the following output:
<?xml version="1.0" encoding="UTF-8" standalone="no"?><doc><name first="David" last="Marston"/>
This time, only the first <name> element was printed out.
At this point, you have 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 will see how to use a transformer to create XML from any data structure you are capable of parsing.