HomeXML Page 3 - XML Parsing With DOM and Xerces (part 2)
Highlights - XML
In this concluding article of a two-part series, use your knowledge of DOM processing with Xerces to construct simple Web applications based on Xerces, XML and JSP. Examples include transforming an XML file to HTML via Xerces and dynamically generating an XML document tree from a MySQL database.
Now, how about something a little more useful? Let's suppose I want to display this same 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:
Here's the code to accomplish this:
import org.apache.xerces.parsers.DOMParser;
import org.xml.sax.SAXException;
import
org.w3c.dom.*;
import java.io.*;
public class MyFifthDomApp {
private Writer
out;
private String local = "";
private Integer Alert, Quantity;
// constructor
public MyFifthDomApp (String xmlFile, Writer out) throws
SAXException
{
this.out = out;
// create a Xerces DOM parser
DOMParser parser = new DOMParser();
// parse the document
// get to the root node's children
// call a recursive function
to process the tree
try {
parser.parse(xmlFile);
Document document = parser.getDocument();
Element
RootElement = document.getDocumentElement();
NodeList Children
= RootElement.getChildNodes();
printData(Children);
out.flush();
} catch (IOException e) {
throw new SAXException(e);
}
}
private
void
printData (NodeList NodeCollection) throws SAXException {
try {
if (NodeCollection != null) {
for (int i=0; i< NodeCollection.getLength();
i++) {
local = NodeCollection.item(i).getNodeName();
if(local.equals("item")) {
// "item" element
starts a new row
out.write("<tr>");
getElementData(NodeCollection.item(i));
printData(NodeCollection.item(i).getChildNodes());
out.write("</tr>");
} else if( local.equals("name")
||
local.equals("supplier")) {
// create table cells within
row
// align strings left
out.write("<td><p
align=left><font face=Verdana
size=2>");
getElementData(NodeCollection.item(i));
printData(NodeCollection.item(i).getChildNodes());
out.write("</font></p></td>");
} else
if( local.equals("id") || local.equals("cost") ||
local.equals("quantity")) {
// create table cells within row
//
align
numbers right
out.write("<td><p align=right><font face=Verdana
size=2>");
getElementData(NodeCollection.item(i));
printData(NodeCollection.item(i).getChildNodes());
out.write("</font></p></td>");
}
}
}
} catch (IOException
e) {
throw
new SAXException(e);
}
}
private void
getElementData(Node parentNode)
throws SAXException {
try {
// get the type of the first
child of the nodeset.
int childType
= parentNode.getFirstChild().getNodeType();
// only proceed further
if it is a text node
if (childType
== Node.TEXT_NODE) {
// get the value stored at the node
String Content = parentNode.getFirstChild().getNodeValue();
// check for whitespace
// proceed only if non-empty
string
if (!Content.trim().equals("")){
//
check
if node needs special handling (does the parent
node has attributes?)
if(parentNode.hasAttributes()) {
// if
parent
has attributes, this one needs special
handling
//
first
get the attributes
NamedNodeMap AttributesList =
parentNode.getAttributes();
// iterate through the collection and get attribute
details
for(int j = 0; j < AttributesList.getLength(); j++) {
// element-specific attribute handling
if ( parentNode.getNodeName().equals("quantity") &&
AttributesList.item(j).getNodeName().equals("alert")
) {
Quantity = new Integer(Content);
Alert = new
Integer(AttributesList.item(j).getNodeValue());
// 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 {
// element has
attributes, but no special
treatment required
out.write(Content);
}
}
} else {
// parent node
has no attributes
// just
display the text
out.write(Content);
}
}
}
} catch (IOException e) {
throw
new SAXException(e);
}
}
}
Before you consider diving out of your window to escape the squiggles above,
you might want to read the explanation - it's nowhere near as complicated as it looks.
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 items that should be in stock of the corresponding item; if the quantity drops below this minimum level, an alert should be generated.
With this in mind, I've designed the class above around two main functions, one to traverse the document tree and the other to actually print the content it finds. And so, I have the printData() function, which recursively processes the document tree, and the getElementData() function, which retrieves the data enclosed with the XML elements.
Let's take a closer look at the different elements of the listing above:
// constructor
public MyFifthDomApp (String xmlFile, Writer out) throws SAXException
{
this.out = out;
// create a Xerces DOM parser
DOMParser
parser
= new DOMParser();
// parse the document
// get to the
root node's
children
// call a recursive function to process the tree
try {
parser.parse(xmlFile);
Document document = parser.getDocument();
Element RootElement = document.getDocumentElement();
NodeList
Children = RootElement.getChildNodes();
printData(Children);
out.flush();
} catch (IOException e) {
throw new SAXException(e);
}
}
If you look at this closely, you'll see that I've been holding out on you a little
in the previous examples. I never told you about the getDocumentElement() method, which lets you immediately access the document (outermost) element of the XML document. Well, now you know.
Once a reference to the document element has been obtained, the nest step is to obtain a list of its children, and hand these over to printData() for processing.