Section 4.2. Setting Up a Simple XML Document


4.2. Setting Up a Simple XML Document

Before we delve into the code, we need to make some decisions. We're going to return data using XML, but how should that XML be structured? What should our XML response look like? We don't want anything complex, so we'll aim to create an XML document that looks like this:

 <converted-values>     <decimal>97</decimal>     <hexadecimal>0x61</hexadecimal>     <octal>0141</octal>     <hyper>&amp;0x61;</hyper>     <binary>1100001B</binary> </converted-values> 

With this format, the browser can use its document object model (DOM) parser to index and retrieve the data.

There are many ways to create this XML document. For the sake of simplicity, we'll first use a StringBuffer to wrap the data with XML tags. Later, we'll look at other ways to create the XML document.

When I talk about XML formatting, I'm referring to the server wrapping the data in XML. The client receives the XML-formatted string in the HTTPResponse and parses it for the individual data fields. The client passes data through the request using either HTTPPost( ) or HTTPGet( ). There is no reason for the client to send XML data to the server, because the data is already wrapped in the request as name/value pairs.


4.2.1. Using a Servlet to Build an XML Document

Let's start by looking at the servlet code that wraps the data in XML. This servlet is shown in Example 4-1.

Example 4-1. The AjaxResponseServlet

 /*  * Converts a character to hex, decimal, binary, octal, and HTML, then  * wraps each of the fields with XML and sends them back through the response.  */ package com.AJAXbook.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class AjaxResponseServlet extends HttpServlet {     public void doGet(HttpServletRequest req, HttpServletResponse res)             throws ServletException, IOException {         // key is the parameter passed in from the JavaScript         // variable named url (see index.html)         String key = req.getParameter("key");         StringBuffer returnXML = null;         if (key != null) {             // extract the first character from key             // as an int, then convert that int to a String             int keyInt = key.charAt(0);             returnXML = new StringBuffer("\r\n<converted-values>");             returnXML.append("\r\n<decimal>"+                              Integer.toString(keyInt)+"</decimal>");             returnXML.append("\r\n<hexadecimal>0x"+                              Integer.toString(keyInt,16)+"</hexadecimal>");             returnXML.append("\r\n<octal>0"+                              Integer.toString(keyInt,8)+"</octal>");             returnXML.append("\r\n<hyper>&amp;0x"+                              Integer.toString(keyInt,16)+";</hyper>");             returnXML.append("\r\n<binary>"+                              Integer.toString(keyInt,2)+"B</binary>");             returnXML.append("\r\n</converted-values>");             // set up the response             res.setContentType("text/xml");             res.setHeader("Cache-Control", "no-cache");             // write out the XML string             res.getWriter().write(returnXML.toString( ));         }         else {             // if key comes back as a null, return a question mark             res.setContentType("text/xml");             res.setHeader("Cache-Control", "no-cache");             res.getWriter( ).write("?");         }     } } 

This code is similar to the code from Chapter 3. The only thing that has been added is the code to wrap the data with XML tags:

 returnXML = new StringBuffer("\r\n<converted-values>"); returnXML.append("\r\n<decimal>"+                  Integer.toString(keyInt)+"</decimal>"); returnXML.append("\r\n<hexadecimal>0x"+                  Integer.toString(keyInt,16)+"</hexadecimal>"); returnXML.append("\r\n<octal>0"+                  Integer.toString(keyInt,8)+"</octal>"); returnXML.append("\r\n<hyper>&amp;0x"+                  Integer.toString(keyInt,16)+";</hyper>"); returnXML.append("\r\n<binary>"+                  Integer.toString(keyInt,2)+"B</binary>"); returnXML.append("\r\n</converted-values>"); 

This code simply sets up a StringBuffer called returnXML. We then convert the incoming value to decimal, hex, etc.; wrap it with an appropriate XML tag; and append it to the buffer. When we've finished all five conversions and added the closing tag (</converted-values>), we send the response back to the Ajax client using res.getWriter().write( ). We return a question mark (without any XML wrapping) if the key we received was null.

4.2.2. Other Ways to Build the XML Document

Building an XML document by appending to a StringBuffer is a common approach, but it's far from ideal, particularly if you need to generate a large document programmatically. Fortunately, there are alternatives.

4.2.2.1. JDOM

One option is to use the JDOM library to write the XML. Download the jdom.jar file from http://www.jdom.org, and put it in your application's WEB-INF/lib directory. Then, instead of writing to a StringBuffer, use JDOM to build the XML, as shown in Example 4-2.

Example 4-2. Using JDOM to create the XML document

 // additional imports needed for JDOM import org.jdom.Document; import org.jdom.Element; import org.jdom.output.XMLOutputter; public String createJdomXML(int key) throws IOException {     Document document = new Document( );     // create root node     Element root = new org.jdom.Element("converted-values");     document.setRootElement(root);     // create your node     org.jdom.Element element = new org.jdom.Element("decimal");     // add content to the node     element.addContent(Integer.toString(key));     // add your node to root     root.addContent(element);     element = new org.jdom.Element("hexadecimal");     element.addContent("0x" + Integer.toString(key, 16));     root.addContent(element);     element = new org.jdom.Element("octal");     element.addContent("0" + Integer.toString(key, 8));     root.addContent(element);     element = new org.jdom.Element("hyper");     element.addContent("&0x" + Integer.toString(key, 16));     root.addContent(element);     element = new org.jdom.Element("binary");     element.addContent(Integer.toString(key, 2) + "B");     root.addContent(element);     // output JDOM document as a String of bytes     XMLOutputter outputter = new XMLOutputter( );     return outputter.outputString(document); } 

In the preceding code, we first create a Document (org.jdom.Document), then an Element named root with the String "converted-values" as its value. That element becomes the root of the XML document. Here's what the document looks like at this point:

 <converted-values> </converted-values> 

To add child elements to the root, we create new elements and add them to the root element. The code that creates the decimal element and adds it to the root element looks like this:

 org.jdom.Element element = new org.jdom.Element("decimal"); element.addContent(Integer.toString(key)); root.addContent(element); 

We repeat this process until we've added all the elements to the root. Then we use an XMLOutputter to format the document into a String that we can send back to the client. The JDOM XML document now looks like this (with linefeeds and spaces added for readability):

 <?xml version="1.0" encoding="UTF-8"?> <converted-values>     <decimal>97</decimal>     <hexadecimal>0x61</hexadecimal>     <octal>0141</octal>     <hyper>&amp;0x61</hyper>     <binary>1100001B</binary> </converted-values> 

4.2.2.2. dom4j

dom4j is an XML library similar in intent to JDOM. After downloading dom4j from http://www.dom4j.org/download.html and installing it in your application's WEB-INF/lib directory, you can use it to create your XML document. As shown in Example 4-3, we create a document, add a root element to the document, add the elements and data to the root, and then return the document in a String.

Example 4-3. Using dom4j to create the XML document

 // additional imports for dom4j import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.OutputFormat; import org.dom4j.io.XMLWriter; ... public String createDom4jXML(int key) throws IOException {     Document document = DocumentHelper.createDocument( );     Element root = document.addElement("converted-values");     Element element = root.addElement("decimal").addText(             Integer.toString(key));     element = root.addElement("hexadecimal").addText(             "0x" + Integer.toString(key, 16));     element = root.addElement("octal").addText("0" + Integer.toString(key, 8));     element = root.addElement("hyper").addText("&0x" + Integer.toString(key, 16));     element = root.addElement("binary").addText(Integer.toString(key, 2) + "B");     StringBuffer xmlDoc = null;     StringWriter sw = new StringWriter( );     OutputFormat outformat = OutputFormat.createPrettyPrint( );     XMLWriter writer = new XMLWriter(sw, outformat);     writer.write(document);     writer.close( );     xmlDoc = sw.getBuffer( );     return xmlDoc.toString( ); } 

The dom4j library uses the static method DocumentHelper.createDocument( ) to create the XML document. The method root.addElement( ) puts a child element on the root element, and addText( ) puts the data in the elements. The OutputFormat class is then used to format the XMLDocument, so the document looks like this:

 <?xml version="1.0" encoding="UTF-8"?> <converted-values>     <decimal>97</decimal>     <hexadecimal>0x61</hexadecimal>     <octal>0141</octal>     <hyper>&amp;0x61</hyper>     <binary>1100001B</binary> </converted-values> 

This step can be skipped, because it only formats the document for readability by adding linefeeds and spaces. Since humans shouldn't need to read this document (unless you are debugging), you won't need the formatting.

To use dom4j without the formatting, simply replace these two lines:

 OutputFormat outformat = OutputFormat.createPrettyPrint( ); XMLWriter writer = new XMLWriter(sw, outformat); 

with this line:

 XMLWriter writer = new XMLWriter(sw); 

4.2.2.3. SAX

SAX, the Simple API for XML, provides another way to create an XML document for an Ajax application. It may be faster than JDOM or dom4J, because it doesn't require building a DOM tree for your document. Start by initializing a StringWriter and a StreamResult. Initialize the StreamResult with the StreamWriter, then get a SAXTransformerFactory and get a transformerHandler from that. The TRansformerHandler allows you to create an XML document by starting a document and appending elements and data to the TRansformerHandler. Example 4-4 shows how it works.

Example 4-4. Using SAX to write out the XML document

 // additional imports for writing XML with SAX import java.io.*; import org.xml.sax.helpers.AttributesImpl; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; public String createSAXXML(int key) {     Writer writer = new StringWriter( );     StreamResult streamResult = new StreamResult(writer);     SAXTransformerFactory transformerFactory =             (SAXTransformerFactory) SAXTransformerFactory.newInstance( );     try {         String data = null;         TransformerHandler transformerHandler =                 transformerFactory.newTransformerHandler( );         transformerHandler.setResult(streamResult);         // start the document         transformerHandler.startDocument( );         // list all the attributes for element         AttributesImpl attr = new AttributesImpl( );         // start writing elements         // every start tag and end tag has to be defined explicitly         transformerHandler.startElement(null,null, "converted-values", null);         transformerHandler.startElement(null,null,"decimal",null);         data = Integer.toString(key, 10);         transformerHandler.characters(data.toCharArray(),0,data.length( ));         transformerHandler.endElement(null,null,"decimal");         transformerHandler.startElement(null,null,"hexadecimal",null);         data = "0x" + Integer.toString(key, 16);         transformerHandler.characters(data.toCharArray(),0,data.length( ));         transformerHandler.endElement(null,null,"hexadecimal");         transformerHandler.startElement(null,null,"octal",null);         data = "0" + Integer.toString(key, 8);         transformerHandler.characters(data.toCharArray(),0,data.length( ));         transformerHandler.endElement(null,null,"octal");         transformerHandler.startElement(null,null,"binary",null);         data = Integer.toString(key, 2)+"B";         transformerHandler.characters(data.toCharArray(),0,data.length( ));         transformerHandler.endElement(null,null,"binary");         transformerHandler.startElement(null,null,"hyper",null);         data = "&0x" +Integer.toString(key, 16);         transformerHandler.characters(data.toCharArray(),0,data.length( ));         transformerHandler.endElement(null,null,"hyper");         transformerHandler.endElement(null,null, "converted-values");         transformerHandler.endDocument( );         transformerHandler.setResult(streamResult);     } catch (Exception e) {         return null;     }     return writer.toString( ); } 

After calling startDocument( ) to begin the document, we must create the elements and add data to them. We create an element by calling startElement( ):

 transformerHandler.startElement(null,null,"binary",null) 

The third element is the only element needed to set up the XML tag, <binary>.

The actual startElement( ) method declaration looks like this:

 public void startElement(String uri, String localName, String qName, Attributes atts) 

The uri parameter is used for the namespace, but since this example does not use a namespace, a null is passed in.

The second parameter, localName, is also used for the namespace and not needed in this example.

The third parameter, qName, is the qualified name.

The last parameter, atts, is used when the element has attributes; pass in null if attributes are not used, as in this case.


To put the data after the element tag, we set a String, data, to the desired value:

 data = Integer.toString(key, 2)+"B"; 

Then we convert the data to a CharArray and pass it into the characters( ) method. The second and third parameters show where processing starts and stops in the CharArray:

 transformerHandler.characters(data.toCharArray(),0,data.length( )); 

Finally, we terminate the element with a call to endElement( ):

 transformerHandler.endElement(null,null,"binary"); 

Each element is created with startElement( ), characters( ), and endElement( ). When all of the elements for the documents have been completed, a call to endDocument( ) is executed and the result is sent to the StreamResult that was set up at the start of the method:

 transformerHandler.endElement(null,null, "converted-values"); transformerHandler.endDocument( ); transformerHandler.setResult(streamResult); 

Finally, the StreamResult is converted to a String by calling toString( ) on the StringWriter. The StreamResult wraps the StringWriter that was set up at the beginning of this method:

 return writer.toString( ); 

The String can then be returned to the calling method.

Using SAX is purportedly a faster and less memory-intensive way to create XML documents than using DOM-based libraries such as JDOM and dom4j. If your testing shows that speed is an issue, or if the SAX API is more natural for your application, you should consider using it.

There are other ways to create an XML document. For example, the Apache project's Element Construction Set (ECS) allows you to create an XML document, but there is no method to add data to the document at this time, so for this application ECS is not useful.





Ajax on Java
Ajax on Java
ISBN: 0596101872
EAN: 2147483647
Year: 2007
Pages: 78

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