Generating XML Documents


You now know how to write Java programs that read XML. Let us now turn to the opposite process, producing XML output. Of course, you could write an XML file simply by making a sequence of print calls, printing the elements, attributes, and text content, but that would not be a good idea. The code is rather tedious, and you can easily make mistakes if you don't pay attention to special symbols (such as " or <) in the attribute values and text content.

A better approach is to build up a DOM tree with the contents of the document and then write out the tree contents. To build a DOM tree, you start out with an empty document. You can get an empty document by calling the newDocument method of the DocumentBuilder class.

 Document doc = builder.newDocument(); 

Use the createElement method of the Document class to construct the elements of your document.

 Element rootElement = doc.createElement(rootName); Element childElement = doc.createElement(childName); 

Use the createTextNode method to construct text nodes:

 Text textNode = doc.createTextNode(textContents); 

Add the root element to the document, and add the child nodes to their parents:

 doc.appendChild(rootElement); rootElement.appendChild(childElement); childElement.appendChild(textNode); 

As you build up the DOM tree, you may also need to set element attributes. Simply call the setAttribute method of the Element class:

 rootElement.setAttribute(name, value); 

Somewhat curiously, the DOM API currently has no support for writing a DOM tree to an output stream. To overcome this limitation, we use the XML Style Sheet Transformations (XSLT) API. We apply the "do nothing" transformation to the document and capture its output. To include a DOCTYPE node in the output, you also need to set the SYSTEM and PUBLIC identifiers as output properties.

 // construct the "do nothing" transformation Transformer t = TransformerFactory.newInstance().newTransformer(); // set output properties to get a DOCTYPE node t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, systemIdentifier); t.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, publicIdentifier); // apply the "do nothing" transformation and send the output to a file t.transform(new DOMSource(doc), new StreamResult(new FileOutputStream(file))); 

For more information about XSLT, turn to the next section. Right now, consider this code a "magic incantation" to produce XML output.

NOTE

The resulting XML file contains no whitespace (that is, no line breaks or indentations). If you like whitespace, set the "OutputKeys.INDENT" property to the string "yes".


Example 12-9 is a typical program that produces XML output. The program draws a modernist paintinga random set of colored rectangles (see Figure 12-6). To save a masterpiece, we use the Scalable Vector Graphics (SVG) format. SVG is an XML format to describe complex graphics in a device-independent fashion. You can find more information about SVG at http://www.w3c.org/Graphics/SVG. To view SVG files, download the Apache Batik viewer (http://xml.apache.org/batik) or the Adobe browser plug-in (http://www.adobe.com/svg/main.html). Figure 12-7 shows the Apache Batik viewer.

Figure 12-6. Generating modern art


Figure 12-7. The Apache Batik SVG viewer


We don't go into details about SVG. If you are interested in SVG, we suggest you start with the tutorial on the Adobe site. For our purposes, we just need to know how to express a set of colored rectangles. Here is a sample:

 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20000802//EN"    "http://www.w3.org/TR/2000/CR-SVG-20000802/DTD/svg-20000802.dtd"> <svg width="300" height="150"> <rect x="231" y="61" width="9" height="12" fill="#6e4a13"/> <rect x="107" y="106" width="56" height="5" fill="#c406be"/> . . . </svg> 

As you can see, each rectangle is described as a rect node. The position, width, height, and fill color are attributes. The fill color is an RGB value in hexadecimal.

NOTE

As you can see, SVG uses attributes heavily. In fact, some attributes are quite complex. For example, here is a path element:

 <path d="M 100 100 L 300 100 L 200 300 z"> 

The M denotes a "moveto" command, L is "lineto," and z is "closepath" (!). Apparently, the designers of this data format didn't have much confidence in using XML for structured data. In your own XML formats, you may want to use elements instead of complex attributes.


Here is the source code for the program. You can use the same technique whenever you need to generate XML output.

Example 12-9. XMLWriteTest.java
   1. import java.awt.*;   2. import java.awt.geom.*;   3. import java.io.*;   4. import java.util.*;   5. import java.awt.event.*;   6. import javax.swing.*;   7. import javax.xml.parsers.*;   8. import javax.xml.transform.*;   9. import javax.xml.transform.dom.*;  10. import javax.xml.transform.stream.*;  11. import org.w3c.dom.*;  12.  13.  14. /**  15.    This program shows how to write an XML file. It saves  16.    a file describing a modern drawing in SVG format.  17. */  18. public class XMLWriteTest  19. {  20.    public static void main(String[] args)  21.    {  22.       XMLWriteFrame frame = new XMLWriteFrame();  23.       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  24.       frame.setVisible(true);  25.    }  26. }  27.  28. /**  29.    A frame with a panel for showing a modern drawing.  30. */  31. class XMLWriteFrame extends JFrame  32. {  33.    public XMLWriteFrame()  34.    {  35.       setTitle("XMLWriteTest");  36.       setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);  37.  38.       chooser = new JFileChooser();  39.  40.       // add panel to frame  41.  42.       panel = new RectanglePanel();  43.       add(panel);  44.  45.       // set up menu bar  46.  47.       JMenuBar menuBar = new JMenuBar();  48.       setJMenuBar(menuBar);  49.  50.       JMenu menu = new JMenu("File");  51.       menuBar.add(menu);  52.  53.       JMenuItem newItem = new JMenuItem("New");  54.       menu.add(newItem);  55.       newItem.addActionListener(new  56.          ActionListener()  57.          {  58.             public void actionPerformed(ActionEvent event) { panel.newDrawing(); }  59.          });  60.  61.       JMenuItem saveItem = new JMenuItem("Save");  62.       menu.add(saveItem);  63.       saveItem.addActionListener(new  64.          ActionListener()  65.          {  66.             public void actionPerformed(ActionEvent event)  67.             {  68.                try  69.                {  70.                   saveDocument();  71.                }  72.                catch (TransformerException e)  73.                {  74.                   JOptionPane.showMessageDialog(  75.                      XMLWriteFrame.this, e.toString());  76.                }  77.                catch (IOException e)  78.                {  79.                   JOptionPane.showMessageDialog(  80.                      XMLWriteFrame.this, e.toString());  81.                }  82.             }  83.          });  84.  85.       JMenuItem exitItem = new JMenuItem("Exit");  86.       menu.add(exitItem);  87.       exitItem.addActionListener(new  88.          ActionListener()  89.          {  90.             public void actionPerformed(ActionEvent event) { System.exit(0); }  91.          });  92.    }  93.  94.    /**  95.       Saves the drawing in SVG format.  96.    */  97.    public void saveDocument()  98.       throws TransformerException, IOException  99.    { 100.       if (chooser.showSaveDialog(this) != JFileChooser.APPROVE_OPTION) return; 101.       File f = chooser.getSelectedFile(); 102.       Document doc = panel.buildDocument(); 103.       Transformer t = TransformerFactory.newInstance().newTransformer(); 104.       t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, 105.          "http://www.w3.org/TR/2000/CR-SVG-20000802/DTD/svg-20000802.dtd"); 106.       t.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "-//W3C//DTD SVG 20000802//EN"); 107. 108.       t.transform(new DOMSource(doc), new StreamResult(new FileOutputStream(f))); 109.    } 110. 111.    public static final int DEFAULT_WIDTH = 300; 112.    public static final int DEFAULT_HEIGHT = 200; 113. 114.    private RectanglePanel panel; 115.    private JFileChooser chooser; 116. } 117. 118. /** 119.    A panel that shows a set of colored rectangles 120. */ 121. class RectanglePanel extends JPanel 122. { 123.    public RectanglePanel() 124.    { 125.       rects = new ArrayList<Rectangle2D>(); 126.       colors = new ArrayList<Color>(); 127.       generator = new Random(); 128. 129.       DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 130.       try 131.       { 132.          builder = factory.newDocumentBuilder(); 133.       } 134.       catch (ParserConfigurationException e) 135.       { 136.          e.printStackTrace(); 137.       } 138.    } 139. 140.    /** 141.       Create a new random drawing. 142.    */ 143.    public void newDrawing() 144.    { 145.       int n = 10 + generator.nextInt(20); 146.       rects.clear(); 147.       colors.clear(); 148.       for (int i = 1; i <= n; i++) 149.       { 150.          int x = generator.nextInt(getWidth()); 151.          int y = generator.nextInt(getHeight()); 152.          int width = generator.nextInt(getWidth() - x); 153.          int height = generator.nextInt(getHeight() - y); 154.          rects.add(new Rectangle(x, y, width, height)); 155.          int r = generator.nextInt(256); 156.          int g = generator.nextInt(256); 157.          int b = generator.nextInt(256); 158.          colors.add(new Color(r, g, b)); 159.       } 160.       repaint(); 161.    } 162. 163.    public void paintComponent(Graphics g) 164.    { 165.       if (rects.size() == 0) newDrawing(); 166.       super.paintComponent(g); 167.       Graphics2D g2 = (Graphics2D) g; 168. 169.       // draw all rectangles 170.       for (int i = 0; i < rects.size(); i++) 171.       { 172.          g2.setPaint(colors.get(i)); 173.          g2.fill(rects.get(i)); 174.       } 175.    } 176. 177.    /** 178.       Creates an SVG document of the current drawing. 179.       @return the DOM tree of the SVG document 180.    */ 181.    public Document buildDocument() 182.    { 183. 184.       Document doc = builder.newDocument(); 185.       Element svgElement = doc.createElement("svg"); 186.       doc.appendChild(svgElement); 187.       svgElement.setAttribute("width", "" + getWidth()); 188.       svgElement.setAttribute("height", "" + getHeight()); 189.       for (int i = 0; i < rects.size(); i++) 190.       { 191.          Color c = colors.get(i); 192.          Rectangle2D r = rects.get(i); 193.          Element rectElement = doc.createElement("rect"); 194.          rectElement.setAttribute("x", "" + r.getX()); 195.          rectElement.setAttribute("y", "" + r.getY()); 196.          rectElement.setAttribute("width", "" + r.getWidth()); 197.          rectElement.setAttribute("height", "" + r.getHeight()); 198.          rectElement.setAttribute("fill", colorToString(c)); 199.          svgElement.appendChild(rectElement); 200.       } 201.       return doc; 202.    } 203. 204.    /** 205.       Converts a color to a hex value. 206.       @param c a color 207.       @return a string of the form #rrggbb 208.    */ 209.    private static String colorToString(Color c) 210.    { 211.       StringBuffer buffer = new StringBuffer(); 212.       buffer.append(Integer.toHexString(c.getRGB() & 0xFFFFFF)); 213.       while(buffer.length() < 6) buffer.insert(0, '0'); 214.       buffer.insert(0, '#'); 215.       return buffer.toString(); 216.    } 217. 218.    private ArrayList<Rectangle2D> rects; 219.    private ArrayList<Color> colors; 220.    private Random generator; 221.    private DocumentBuilder builder; 222. } 


 javax.xml.parsers.DocumentBuilder 1.4 

  • Document newDocument()

    returns an empty document.


 org.w3c.dom.Document 1.4 

  • Element createElement(String name)

    returns an element with the given name.

  • Text createTextNode(String data)

    returns a text node with the given data.


 org.w3c.dom.Node 1.4 

  • Node appendChild(Node child)

    appends a node to the list of children of this node. Returns the appended node.


 org.w3c.dom.Element 1.4 

  • void setAttribute(String name, String value)

    sets the attribute with the given name to the given value.

  • void setAttributeNS(String uri, String qname, String value)

    sets the attribute with the given namespace URI and qualified name to the given value.

    Parameters:

    uri

    The URI of the namespace, or null

     

    qname

    The qualified name. If it has an alias prefix, then uri must not be null

     

    value

    The attribute value



 javax.xml.transform.TransformerFactory 1.4 

  • static TransformerFactory newInstance()

    returns an instance of the TRansformerFactory class.

  • transformer newTransformer()

    returns an instance of the transformer class that carries out an identity or "do nothing" transformation.


 javax.xml.transform.Transformer 1.4 

  • void setOutputProperty(String name, String value)

    sets an output property. See http://www.w3.org/TR/xslt#output for a listing of the standard output properties. The most useful ones are shown below:

    Parameter:

    doctype-public

    The public ID to be used in the DOCTYPE declaration

     

    doctype-system

    The system ID to be used in the DOCTYPE declaration

     

    indent

    yes or no


  • void transform(Source from, Result to)

    transforms an XML document.


 javax.xml.transform.dom.DOMSource 1.4 

  • DOMSource(Node n)

    constructs a source from the given node. Usually, n is a document node.


 javax.xml.transform.stream.StreamResult 1.4 

  • StreamResult(File f)

  • StreamResult(OutputStream out)

  • StreamResult(Writer out)

  • StreamResult(String systemID)

    construct a stream result from a file, stream, writer, or system ID (usually a relative or absolute URL).



    Core JavaT 2 Volume II - Advanced Features
    Building an On Demand Computing Environment with IBM: How to Optimize Your Current Infrastructure for Today and Tomorrow (MaxFacts Guidebook series)
    ISBN: 193164411X
    EAN: 2147483647
    Year: 2003
    Pages: 156
    Authors: Jim Hoskins

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net