Logo         Community
  Trog
Services
The Company
Community
Columns
Your Account
Contact Us
 
 
XML Parsing With SAX and Xerces (part 2)
Get down and dirty with the Xerces SAX parser.

| Nailing It To The Wall |

Now, how about something a little more useful? Consider the following modification of the previous example:


<?xml version="1.0"?>
<inventory>
<item>
<id>758</id>
<name>Rusty, jagged nails for nailgun</name>
<supplier>NailBarn, Inc.</supplier>
<cost>2.99</cost>
<quantity alert="500">10000</quantity>
</item>
<item>
<id>6273</id>
<name>Power pack for death ray</name>
<supplier>QuakePower.domain.com</supplier>
<cost currency="USD">9.99</cost>
<quantity alert="20">10</quantity>
</item>
<item>
<id>3784</id>
<name>Axe</name>
<supplier>Axe And You Shall Receive, Inc.</supplier>
<cost currency="USD">56.74</cost>
<quantity alert="5">25</quantity>
</item>
<item>
<id>986</id>
<name>NVGs</name>
<supplier>Quake Eyewear</supplier>
<cost currency="USD">1399.99</cost>
<quantity alert="5">2</quantity>
</item>
</inventory>


Now, let's suppose I want to display this information in a neatly-formatted table, with those items that I'm low on highlighted in red. My preferred output would look something like this:

Output image

Here's the code to accomplish this:


import org.apache.xerces.parsers.SAXParser;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;
import java.io.*;

public class MyFifthSaxApp extends DefaultHandler {

private Writer out;
private String ElementName, AttributeName,AttributeValue = "";
private Integer Quantity, Alert;

    // constructor
    public MyFifthSaxApp (String xmlFile, Writer out)
throws SAXException {

this.out = out;

        //  Create a Xerces SAX parser
        SAXParser parser = new SAXParser();

//  Set the Content Handler
        parser.setContentHandler(this);

        //  parse the Document
        try {
            parser.parse(xmlFile);
out.flush();
                  } catch (IOException e) {
            throw new SAXException(e);
            }
    }

    // call this when opening element found
    public void startElement (String uri, String local, String qName, Attributes atts) 
throws SAXException {
try {

// this is useful later
ElementName = local;

// display table header
if(local.equals("inventory")) {
out.write("<h1><font face=Verdana>Inventory Management</font></h1>\n<table width=\"55%\" cellpadding=\"5\" cellspacing=\"5\" border=\"1\"><tr><td><p align=right><b><font face=Verdana size=2>Code</font></b></p></td><td><b><font face=Verdana size=2>Name</font></b></td><td><b><font face=Verdana size=2>Supplier</font></b></td><td><p align=right><b><font face=Verdana size=2>Cost</font></b></p></td><td><p align=right><font face=Verdana size=2><b>Quantity</b></font></p></td></tr>");
} else if(local.equals("item")) {
// "item" element starts a new row
out.write("<tr>");
} else if( local.equals("name") || local.equals("supplier")) {
// create table cells within row
// align strings left, numbers right
out.write("<td><p align=left><font face=Verdana size=2>");
} else if( local.equals("id") || local.equals("cost") || local.equals("quantity")) {
out.write("<td><p align=right><font face=Verdana size=2>");
} else {
out.write("<br>");
}

for (int i = 0; i < atts.getLength(); i++) {
AttributeName = atts.getLocalName(i);
AttributeValue = atts.getValue(AttributeName);
if(AttributeName.equals("currency")) {
out.write(AttributeValue + "&nbsp;");
} else if(AttributeName.equals("alert")) {
Alert = new Integer(AttributeValue);
} else {
out.write("&nbsp;");
}
        }
} catch (IOException e) {
throw new SAXException(e);
}
}

// call this when cdata found
    public void characters(char[] text, int start, int length)
throws SAXException {
  try {
String Content = new String(text, start, length);
        if (!Content.trim().equals("")) {
if ((ElementName != null && ElementName.equals("quantity")) && (AttributeName != null && AttributeName.equals("alert"))) {
Quantity = new Integer(Content);
// if quantity lower than expected, highlight in red
if((Quantity.intValue()) < (Alert.intValue())) { out.write("<font color=\"#ff0000\">" + Quantity + "</font>");
} else {
out.write("<font color=\"#000000\">" + Quantity + "</font>");
}

} else {
out.write(Content);
}
}
} catch (IOException e) {
throw new SAXException(e);
}
    }

//  call this when closing element found
public void endElement (String uri, String local, String qName)
throws SAXException {
try {
if(local.equals("inventory")) {
out.write("</table>");
} else if(local.equals("item")) {
// "item" closes table row
out.write("</tr>");
} else if(local.equals("id") || local.equals("name") || local.equals("supplier") || local.equals("cost") || local.equals("quantity")) {
// close table cells
out.write("</font></p></td>");
} else {
out.write("&nbsp;");
}
} catch (IOException e) {
throw new SAXException(e);
}
}

}


As you can see, the callback functions used here have evolved substantially from the previous examples - they now contain more conditional tests, and better error handling capabilities. Let's take a closer look.

Most of the work in this script is done by the startElement() callback function. This function prints specific HTML output depending on the element encountered by the parser.


// call this when opening element found
    public void startElement (String uri, String local, String qName, Attributes atts) 
throws SAXException {
try {

// this is useful later
ElementName = local;

// display table header
if(local.equals("inventory")) {
out.write("<h1><font face=Verdana>Inventory Management</font></h1>\n<table width=\"55%\" cellpadding=\"5\" cellspacing=\"5\" border=\"1\"><tr><td><p align=right><b><font face=Verdana size=2>Code</font></b></p></td><td><b><font face=Verdana size=2>Name</font></b></td><td><b><font face=Verdana size=2>Supplier</font></b></td><td><p align=right><b><font face=Verdana size=2>Cost</font></b></p></td><td><p align=right><font face=Verdana size=2><b>Quantity</b></font></p></td></tr>");
} else if(local.equals("item")) {
// "item" element starts a new row
out.write("<tr>");
} else if( local.equals("name") || local.equals("supplier")) {
// create table cells within row
// align strings left, numbers right
out.write("<td><p align=left><font face=Verdana size=2>");
} else if( local.equals("id") || local.equals("cost") || local.equals("quantity")) {
out.write("<td><p align=right><font face=Verdana size=2>");
} else {
out.write("<br>");
}

for (int i = 0; i < atts.getLength(); i++) {
AttributeName = atts.getLocalName(i);
AttributeValue = atts.getValue(AttributeName);
if(AttributeName.equals("currency")) {
out.write(AttributeValue + "&nbsp;");
} else if(AttributeName.equals("alert")) {
Alert = new Integer(AttributeValue);
} else {
out.write("&nbsp;");
}
        }
} catch (IOException e) {
throw new SAXException(e);
}
}


This function maps different XML elements to appropriate HTML markup. As you can see, the document element "inventory", which marks the start of the XML document, is used to create the skeleton and first row of an HTML table, while the different "item" elements correspond to rows within this table. The details of each item - name, supplier, quantity et al - are formatted as cells within each row of the table.

Next, the characters() callback function handles formatting of the content embedded within the elements.


// call this when cdata found
    public void characters(char[] text, int start, int length)
throws SAXException {
  try {
String Content = new String(text, start, length);
        if (!Content.trim().equals("")) {
if ((ElementName != null && ElementName.equals("quantity")) && (AttributeName != null && AttributeName.equals("alert"))) {
Quantity = new Integer(Content);
// if quantity lower than expected, highlight in red
if((Quantity.intValue()) < (Alert.intValue())) { out.write("<font color=\"#ff0000\">" + Quantity + "</font>");
} else {
out.write("<font color=\"#000000\">" + Quantity + "</font>");
}

} else {
out.write(Content);
}
}
} catch (IOException e) {
throw new SAXException(e);
}
    }


For most of the elements, I'm simply displaying the content as is. The only deviation from this standard policy occurs with the "quantity" element, which has an additional "alert" attribute. This "alert" attribute specifies the minimum number of units that should be in stock of the corresponding item; if the quantity drops below this minimum level, an alert should be generated. Consequently, the characters() callback includes some code to test the current quantity against the minimum quantity, and highlight the data in red if the test fails.

And finally, to wrap things up, the endElement() callback closes the HTML tags opened earlier.


//  call this when closing element found
public void endElement (String uri, String local, String qName)
throws SAXException {
try {
if(local.equals("inventory")) {
out.write("</table>");
} else if(local.equals("item")) {
// "item" closes table row
out.write("</tr>");
} else if(local.equals("id") || local.equals("name") || local.equals("supplier") || local.equals("cost") || local.equals("quantity")) {
// close table cells
out.write("</font></p></td>");
} else {
out.write("&nbsp;");
}
} catch (IOException e) {
throw new SAXException(e);
}
}


Once you've compiled this class, you can use it in a JSP page, as you did with the previous example. Here's the code,


<%@ page language="java" import="java.io.IOException" %>
<html>
<head>
</head>
<body>

<%
try {
MyFifthSaxApp myFifthExample = new MyFifthSaxApp("/www/xerces/WEB-INF/classes/inventory.xml",out);
} catch (Exception e) {
      out.println("<font face=\"verdana\" size=\"2\">The following error occurred: <br><b>" + e + "</b></font>");
}
%>
</body>
</html>


and here's the output:

Output image


How to do Everything with PHP & MySQL
How to do Everything with PHP & MySQL, the best-selling book by Melonfire, explains how to take full advantage of PHP's built-in support for MySQL and link the results of database queries to Web pages. You'll get full details on PHP programming and MySQL database development, and then you'll learn to use these two cutting-edge technologies together. Easy-to-follow sample applications include a PHP online shopping cart, a MySQL order tracking system, and a PHP/MySQL news publishing system.

Read more, or grab your copy now!


previous page more like this  print this article  next page
 
Search...
 
In trog...
Logging With PHP
Building A Quick-And-Dirty PHP/MySQL Publishing System
Output Buffering With PHP
Date/Time Processing With PHP
Creating Web Calendars With The PEAR Calendar Class
more...
 
In the hitg report...
Crime Scenes
Animal Attraction
Lord Of The Strings
more...
 
In boombox...
Patience - George Michael
Think Tank - Blur
My Private Nation - Train
more...
 
In colophon...
Hostage - Robert Crais
The Dead Heart - Douglas Kennedy
Right As Rain - George Pelecanos
more...
 
In cut!...
American Chai
The Core
Possession
more...
 
Find out how you can use this article on your own Web site!


Copyright © 1998-2018 Melonfire. All rights reserved
Terms and Conditions | Feedback