Example 18-1 illustrates how you might use the interfaces discussed in this chapter in a typical programming situation. This application takes a document that uses the furniture.dtd sample DTD from Chapter 20 and validates that the parts list included in the document matches the actual parts used within the document.
/** * PartsCheck.java * * DOM Usage example from the O'Reilly _XML in a Nutshell_ book. * */ // 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.oreilly.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 bookcase.xml sample document from Chapter 20, 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.
Copyright © 2002 O'Reilly & Associates. All rights reserved.