Book HomeXML in a NutshellSearch this book

18.7. A Simple DOM Application

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.

Example 18-1. Parts checker application

/**
 * 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.



Library Navigation Links

Copyright © 2002 O'Reilly & Associates. All rights reserved.