Generating XML

I l @ ve RuBoard

At the beginning of this chapter, you learned about using XML as a medium for doing data interchange. Suppose you want to send a vendor an XML file with order data in it. You could just write a method that creates the XML manually using prints, but this is dangerous because you might forget to include an end tag or you might make some other simple syntactic XML mistake. You can use DOM to generate a file on the fly from database data and be assured that it will be formatted as proper XML. Again, you need to start by defining a DTD for the XML file that's going to hold your orders (see Listing 14.7)

Listing 14.7 Order.dtd
 <?xml version='1.0' encoding='UTF-8' ?> <!ELEMENT File (Order)*> <!ELEMENT Order (email_address, address, credit_card, order_date, order_subtotal,                  order_tax, order_shipping, order_total, items)> <!ATTLIST Order  order_id    CDATA     #REQUIRED > <!ELEMENT email_address (#PCDATA)> <!ELEMENT order_date (#PCDATA)> <!ELEMENT order_subtotal (#PCDATA)> <!ELEMENT order_tax (#PCDATA)> <!ELEMENT order_shipping (#PCDATA)> <!ELEMENT order_total (#PCDATA)> <!ELEMENT address (address_id, first_name, last_name, street_1, street_2, city, state, graphics/ccc.gif postal_code)> <!ATTLIST address address_id CDATA #REQUIRED> <!ELEMENT first_name (#PCDATA)> <!ELEMENT last_name (#PCDATA)> <!ELEMENT street_1 (#PCDATA)> <!ELEMENT street_2 (#PCDATA)> <!ELEMENT city (#PCDATA)> <!ELEMENT state (#PCDATA)> <!ELEMENT postal_code (#PCDATA)> <!ELEMENT credit_card (address, card_type, card_number, card_ownername, card_exp month,                        card_expyear) <!ATTLIST credit_card card_id CDATA #REQUIRED> <!ELEMENT card_type (#PCDATA)> <!ELEMENT card_number (#PCDATA)> <!ELEMENT card_ownername (#PCDATA)> <!ELEMENT card_expmonth (#PCDATA)> <!ELEMENT card_expyear (#PCDATA)> <!ELEMENT items (item)*> <!ELEMENT item (product_isbn, product_title, quantity, unit_price, total_price)> <!ELEMENT product_isbn (#PCDATA)> <!ELEMENT product_title (#PCDATA)> <!ELEMENT quantity (#PCDATA)> <!ELEMENT unit_price (#PCDATA)> <!ELEMENT total_price (#PCDATA)> 

Notice that the address element inside the credit card element is reused rather than duplicating fields.

Now you can write your exporter (see Listing 14.8). You need a number of new imports to make this work, including all the SQL, most of the BFG classes, and some new XML ones.

Listing 14.8 DOMOrderExporter.java
 package com.bfg.xml; import org.apache.xerces.dom.TextImpl; import org.xml.sax.SAXParseException; import org.apache.xerces.parsers.DOMParser; import org.apache.turbine.services.db.TurbineDB; import org.apache.turbine.util.db.pool.DBConnection; import org.apache.turbine.util.TurbineConfig; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.Element; import org.w3c.dom.DOMImplementation; import org.w3c.dom.DocumentType; import java.io.*; import java.sql.*; import java.util.HashMap; import java.util.Vector; import java.util.Iterator; import java.text.NumberFormat; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.ResourceBundle; import org.apache.xml.serialize.Serializer; import org.apache.xml.serialize.XMLSerializer; import org.apache.xml.serialize.OutputFormat; import com.bfg.product.Order; import com.bfg.customer.Address; import com.bfg.customer.CreditCard; import com.bfg.cart.CartItem; import org.apache.xerces.dom.DocumentTypeImpl; import org.apache.xerces.dom.DOMImplementationImpl; import org.apache.xerces.dom.DocumentImpl; public class DOMOrderExporter  {     private static final String     DEFAULT_PARSER_NAME = "org.apache.xerces.parsers.DOMParser";     private static ResourceBundle sql_bundle =       ResourceBundle.getBundle("com.bfg.xml.SQLQueries");     public static void printOrders() {       DOMOrderExporter myclass = new DOMOrderExporter();         try {             DOMParser parser =             (DOMParser)Class.forName(DEFAULT_PARSER_NAME).newInstance();          parser.setFeature("http://xml.org/sax/features/validation", true);          DOMImplementation domImpl = new DOMImplementationImpl();          DocumentType docType = null;             docType = domImpl.createDocumentType( "File", null, "Order.dtd" );          Document document = new DocumentImpl(docType);          Element root = document.createElement("File");          document.appendChild(root);          Iterator orders = Order.getAllOrders().iterator();          while(orders.hasNext()) {              Order order = (Order) orders.next();              myclass.generateOrder(order, document, root);          }             OutputFormat    format  = new OutputFormat( document );           format.setIndent(3);             FileWriter  stringOut = new FileWriter("orders.xml");             XMLSerializer    serial = new XMLSerializer( stringOut, format );             serial.asDOMSerializer();             serial.serialize( document.getDocumentElement() );         }  catch (org.xml.sax.SAXException se) {             if (se.getException() != null)                 se.getException().printStackTrace(System.err);             else                 se.printStackTrace(System.err);         }  catch (Exception e) {             e.printStackTrace(System.err);         }     }     public void addElement(Document document, Node node, String name, String value) {       Node tmp = document.createElement(name);       tmp.appendChild(document.createTextNode(value));       node.appendChild(tmp);     }     public void generateOrder(Order order, Document document, Element root) {       Element order_el = document.createElement("order");                order_el.setAttribute("order_id", String.valueOf(order.getOrderNumber()));                root.appendChild(order_el);                addElement(document, order_el, "email_address",          order.getCustomer().getEmail());                Node addr = generateAddress(order.getAddress(), document);                order_el.appendChild(addr);                Element credit_card = document.createElement("credit_card");                CreditCard card = order.getCreditCard();                 credit_card.appendChild(generateAddress(card.getAddress(), document));                credit_card.setAttribute("card_id", String.valueOf(card.getCardID()));                addElement(document, credit_card, "card_type", card.getCardType());               addElement(document, credit_card, "card_ownername", card.getCardOwner());                addElement(document, credit_card, "card_number", card.getCardNumber()); addElement(document, credit_card, "card_expmonth", String.valueOf(card.get ExpMonth()));                addElement(document, credit_card, "card_expyear", String.valueOf(card. graphics/ccc.gif getExpYear()));                addElement(document, order_el, "order_date", order.getOrderDate().toString( graphics/ccc.gif ));                addElement(document, order_el, "order_subtotal", String.valueOf(order. graphics/ccc.gif getOrderSubtotal()));                addElement(document, order_el, "order_shipping", String.valueOf(order. graphics/ccc.gif getOrderShipping()));                addElement(document, order_el, "order_tax", String.valueOf(order.getOrder graphics/ccc.gif Tax()));                addElement(document, order_el, "order_total", String.valueOf(order. graphics/ccc.gif getOrder Total()));                Element items_el = document.createElement("items");                order_el.appendChild(items_el);                Iterator items = order.getItems().iterator();                while (items.hasNext()) {                    CartItem item = (CartItem) items.next();                    Element item_el = document.createElement("item");                    items_el.appendChild(item_el);                    addElement(document, item_el, "product_isbn", item.getProduct(). graphics/ccc.gif getISBN());                    addElement(document, item_el, "product_title", item.getProduct(). graphics/ccc.gif getTitle());                    addElement(document, item_el, "quantity", String.valueOf(item. graphics/ccc.gif getQuantity()));                    addElement(document, item_el, "unit_price", String.valueOf(item. graphics/ccc.gif getProduct().getPrice()));                    addElement(document, item_el, "total_price", String.valueOf(item.get graphics/ccc.gif LineItemPrice()));        }     }     public Node generateAddress(Address addr, Document document) {       Element tmp = document.createElement("address");       tmp.setAttribute("address_id", String.valueOf(addr.getAddressID()));       addElement(document, tmp, "first_name", addr.getFirstName());       addElement(document, tmp, "last_name", addr.getLastName());       addElement(document, tmp, "street_1", addr.getStreet1());       addElement(document, tmp, "street_2", addr.getStreet2());       addElement(document, tmp, "city", addr.getCity());       addElement(document, tmp, "state", addr.getState());       addElement(document, tmp, "postal_code", addr.getPostalCode());       return tmp;     }     public static void main(String argv[]) {       TurbineConfig tc = new TurbineConfig("./",                                                 "TurbineResources.properties");        tc.init();         if (argv.length == 0) {             System.exit(1);         }       printOrders();     } 

Even though content is being generated instead of being parsed, you still use the same DOM parser class.

To start fresh, create a DomImplementationImpl . When you have it, use it to create a document type so that you can get the right doctype tag at the top of the file that will reference your DTD. Then use the document type to request a DocumentImpl , which will serve as the top of your XML hierarchy.

Just as you had to walk through the tree of nodes when you were unpacking the XML object, now you have to build the tree, starting with the top-level File element. Adding an element to the document consists of two steps. First you create a new element against the document. Then you append it to the node of which you want it to be a child.

After the root node is set up, the method needs to iterate over the orders and create a child Order node for each one. When that's done, it uses the XMLSerializer to write the XML to orders.xml.

You are going to spend a lot of time writing code to add nodes with text content, which normally takes three steps. addElement is a helper function to simplify things. generateOrder does the actual work of producing the XML for each order.

Generating each order is just a matter of creating the appropriate element and subelements to hold all the values. Because the method needs to write out two addresses, break it into a separate function, generateAddress .

Because you're going to be using classes that depend on connection pooling from Turbine, you can't take a shortcut as was done with the importers when a direct database connection was opened. You need to initialize Turbine.

You also need to add something to Order to get all the orders (see Listing 14.9).

Listing 14.9 Additions to Order.java
 public static Vector getAllOrders() {       Vector orders = new Vector();       DBConnection dbConn = null;       try           {               dbConn = TurbineDB.getConnection();               if (dbConn == null) {                  cat.error("Can't get database connection");               }               PreparedStatement pstmt =                    dbConn.prepareStatement(sql_bundle.getString("allOrders"));               ResultSet rs = pstmt.executeQuery();               while (rs.next()) {                    orders.add(Order.findOrder(rs.getInt("ORDER_ID")));               }               rs.close();               pstmt.close();          }        catch (Exception e)          {                cat.error("Error during getOrderHistory", e);          }        finally          {                    try                         {                              TurbineDB.releaseConnection(dbConn);                         }                     catch (Exception e)                         {                              cat.error("Error during release connection", e);           }        }    return orders; } 

The allOrders query is very simple:

 allOrders=SELECT ORDER_ID FROM ORDERS 

Now you can modify your build.xml to run this class instead. When you do an ant testxml , you'll get a perfectly formatted XML document with your orders (or, in this case, order). Listing 14.10 shows the output.

Listing 14.10 An XML Order
 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE File SYSTEM "Order.dtd"> <File>    <order order_id="1">       <email_address>turner@blackbear.com</email_address>       <address address_id="27">          <first_name>Jimmy&apos;s</first_name>          <last_name>Mom</last_name>          <street_1>The Old Farm</street_1>          <street_2/>          <city>Hicksville</city>          <state>OH</state>          <postal_code>44546</postal_code>       </address>       <order_date>2001-11-19</order_date>       <order_subtotal>309.93</order_subtotal>       <order_shipping>8.25</order_shipping>       <order_tax>30.993</order_tax>       <order_total>349.173</order_total>       <items>          <item>             <product_isbn>672321173</product_isbn>             <product_title>Oracle and Java Development</product_title>             <quantity>4</quantity>             <unit_price>39.99</unit_price>             <total_price>159.96</total_price>          </item>          <item>             <product_isbn>PALMCASE</product_isbn>             <product_title>Genuine Nagahyde PDA Carrying Case</product_title>             <quantity>1</quantity>             <unit_price>25.0</unit_price>             <total_price>0.0</total_price>          </item>          <item>             <product_isbn>672320959</product_isbn>             <product_title>Java 2 Micro Edition (J2ME) Application Development</ graphics/ccc.gif product_title>             <quantity>3</quantity>             <unit_price>49.99</unit_price>             <total_price>149.97</total_price>          </item>       </items>    </order> </File> 
I l @ ve RuBoard


MySQL and JSP Web Applications. Data-Driven Programming Using Tomcat and MySQL
MySQL and JSP Web Applications: Data-Driven Programming Using Tomcat and MySQL
ISBN: 0672323095
EAN: 2147483647
Year: 2002
Pages: 203
Authors: James Turner

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