A Simple DOM Application

Example 18-1 illustrates how you might use the interfaces discussed in this chapter in a typical developing situation. This application takes a document that uses the furniture.dtd sample DTD from and validates that the parts list included in the document matches the actual parts used within the document.

Example 18-1. Parts checker application

/** * PartsCheck.java * * DOM Usage example from the Anonymous _XML tutorial_ tutorial. * */ // we'll use the Apache Software Foundation's Xerces parser. import org.apache.xerces.parsers.*; import org.apache.xerces.framework.*; // import the DOM and SAX interfaces import org.w3c.dom.*; import org.xml.sax.*; // get the necessary java support classes import java.io.*; import java.util.*; /** * This class is designed to check the parts list of an XML document that * represents a piece of furniture for validity. It uses the DOM to * analyze the actual furniture description and then check it against the * parts list that is embedded in the document. */ public class PartsCheck {
 // static constants public static final String FURNITURE_NS = "http://namespaces.anonymous.com/furniture/"; // contains the true part count, keyed by part number HashMap m_hmTruePartsList = new HashMap( ); /** * The main function that allows this class to be invoked from the command * line. Check each document provided on the command line for validity. */ public static void main(String[] args) {
 PartsCheck pc = new PartsCheck( ); try {
 for (int i = 0; i < args.length; i++) {
 pc.validatePartsList(args[i]);
}
} catch (Exception e) {
 System.err.println(e);
}
} /** * Given a system identifier for an XML document, this function compares * the actual parts used to the declared parts list within the document. It * prints warnings to standard error if the lists don't agree. */ public void validatePartsList(String strXMLSysID) throws IOException, SAXException {
 // create a new parser DOMParser dp = new DOMParser( ); // parse the document and get the DOM Document interface dp.parse(strXMLSysID); Document doc = dp.getDocument( ); // get an accurate parts list count countParts(doc.getDocumentElement( ), 1); // compare it to the parts list in the document reconcilePartsList(doc);
}
/** * Updates the true parts list by adding the count to the current count * for the part number given. */ private void recordPart(String strPartNum, int cCount) {
 if (!m_hmTruePartsList.containsKey(strPartNum)) {
 // this part isn't listed yet m_hmTruePartsList.put(strPartNum, new Integer(cCount));
}
else {
 // update the count Integer cUpdate = (Integer)m_hmTruePartsList.get(strPartNum); m_hmTruePartsList.put(strPartNum, new Integer(cUpdate.intValue( ) + cCount));
}
} /** * Counts the parts referenced by and below the given node. */ private void countParts(Node nd, int cRepeat) {
 // start the local repeat count at 1 int cLocalRepeat = 1; // make sure we should process this element if (FURNITURE_NS.equals(nd.getNamespaceURI( ))) {
 Node ndTemp; if ((ndTemp = nd.getAttributes( ).getNamedItem("repeat")) != null) {
 // this node specifies a repeat count for its children cLocalRepeat = Integer.parseInt(ndTemp.getNodeValue( ));
}
if ((ndTemp = nd.getAttributes( ).getNamedItem("part_num")) != null) {
 // start the count at 1 int cCount = 1; String strPartNum = ndTemp.getNodeValue( ); if ((ndTemp = nd.getAttributes( ).getNamedItem("count")) != null) {
 // more than one part needed by this node cCount = Integer.parseInt(ndTemp.getNodeValue( ));
}
// multiply the local count by the repeat passed in from the parent cCount *= cRepeat; // add the new parts count to the total recordPart(strPartNum, cCount);
}
} // now process the children NodeList nl = nd.getChildNodes( ); Node ndCur;
for (int i = 0; i < nl.getLength( ); i++) {
 ndCur = nl.item(i); if (ndCur.getNodeType( ) == Node.ELEMENT_NODE) {
 // recursively count the parts for the child, using the local repeat countParts(ndCur, cLocalRepeat);
}
}
}
/** * This method reconciles the true parts list against the list in the document. */ private void reconcilePartsList(Document doc) {
 Iterator iReal = m_hmTruePartsList.keySet().iterator( ); String strPartNum; int cReal; Node ndCheck; // loop through all of the parts in the true parts list while (iReal.hasNext( )) {
 strPartNum = (String)iReal.next( ); cReal = ((Integer)m_hmTruePartsList.get(strPartNum)).intValue( ); // find the part list element in the document ndCheck = doc.getElementById(strPartNum); if (ndCheck == null) {
 // this part isn't even listed! System.err.println("missing <part_name> element for part #" + strPartNum + " (count " + cReal + ")");
}
else {
 Node ndTemp; if ((ndTemp = ndCheck.getAttributes( ).getNamedItem("count")) != null) {
 int cCheck = Integer.parseInt(ndTemp.getNodeValue( )); if (cCheck != cReal) {
 // counts don't agree System.err.println("<part_name> element for part #" + strPartNum + " is incorrect: true part count = " + cReal + " (count in document is " + cCheck + ")");
}
} else {
 // they didn't provide a count for this part! System.err.println("missing count attribute for part #" + strPartNum + " (count " + cReal + ")");
}
}
}
} }

When this application is run over the tutorialcase.xml sample document from , it generates the following output:

missing count attribute for part #HC (count 8) <part_name> element for part #A is incorrect: true part count = 2 (count in document is 1)

To compile and use this sample application, download and install the Xerces Java Parser from the Apache-XML project (http://xml.apache.org/xerces-j). The code was compiled and tested with Sun's JDK Version 1.3.1.