Next UseDOM.java Download this source file



// UseDOM.java.  This program parses an XML file and produces HTML
// output.  The URI of the XML file (ex: "TechTipArchive.xml")
// and the output file name (ex: "ListTipsByAuthor.htm") must be
// provided on the command line.
//
// The sample xml file contains XML elements of authors and tips.
// The program reads the XML file, builds a DOM tree, and gets all
// the author elements (and saves them in a HashMap).
//
// An output DOM is created with an HTML element at the root.  After
// adding a title, the first author is added as an HTML "H2" element,
// then the imput DOM is searched for all tip elements that have that
// author as an attribute.  Each such tip is then added to the output
// DOM as an HTML link ("A HREF" tag).
//
// After processing all the tips for one author, the next author's
// tips are added to the output DOM in the same way.
//
// If all we wanted was to output a modified XML document, we'd be done.
// (By adding XSL styles, this is not a bad solution!)  But to output
// HTML, each node (element) in the output DOM must be printed as
// HTML.  Since DOM elements contain other elements, this is a
// recursive process.  Using Sun's "JAXP" parser, you can simply
// call an element's "toString() method to convert it to an HTML
// tag.  Sadly this is not standard (yet?), so you must write your
// own "print" method to do this.  The print method used here is a
// modified version of DOMWriter.java sample code that comes with
// xerces-j.  (The original outputs XML not HTML.)
// Note that print uses a "normalize" method, to replace reserved
// symbols in the text such as "<" and "&" with character entities
// such as "&lt;" and "&amp;".
//
// Adapted by Wayne Pollock, Tampa Florida USA, 2/2001,
// from an article appearing on Sun's JDC (Jaca Developer Connection).
// (See: http://developer.java.sun.com/.)

import java.io.*;
import java.net.*;
import java.util.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;

public class UseDOM
{
   private Document outputDoc;
   private Element body;
   private Element html;
   private StringBuffer out;
   private HashMap authors = new HashMap();

   public String toString()
   {  if ( html != null )
      {  out = new StringBuffer( "" );
         print( html );
         return out.toString();
      }
      return super.toString();
   }

   public void processWithDOM(String urlString) throws Exception
   {
      System.out.println( "Processing URL " + urlString );

      // Create a new DOM parser object, by first creating a factory object:
      DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
      DocumentBuilder db = dbf.newDocumentBuilder();

      // Create the DOM (a "Document" object):
      Document doc = db.parse(urlString);

      // Get the root element from the xml:
      Element elem = doc.getDocumentElement();

      // Get a list of all "author tags in the document:
      NodeList authorList = elem.getElementsByTagName( "author" );

      for ( int i = 0; i < authorList.getLength(); ++i )
      {
         // Author tags have two attributes (and no data), id and fullName.
         // Use these to build a HashMap of names, using the id as the key:
         Element author = (Element) authorList.item( i );
         String id = author.getAttribute( "id" );
         String fullName = author.getAttribute( "fullName" );

         // Create an HTML "H2" tag, followed by the author's name as text:
         Element h2 = outputDoc.createElement( "H2" );
         body.appendChild( h2 );
         h2.appendChild( outputDoc.createTextNode( "by " + fullName ) );

         // For each author we will add a list of tips, so create an HTML "OL"
         // element, add to output DOM:
         Element list = outputDoc.createElement( "OL" );
         body.appendChild( list );

         // Finally add the (empty) OL list of tips to the HashMap,
         // using the author's ID as the key:
         authors.put( id, list );
      }

      // Now build a list of all "tip" elements from the input:
      NodeList tipsList = elem.getElementsByTagName( "tip" );
      for ( int i = 0; i < tipsList.getLength(); ++i ) 
      {  // Fetch the tip and get its attributes:
         Element tip = (Element) tipsList.item( i );
         String title = tip.getAttribute( "title" );
         String htmlURL = tip.getAttribute( "htmlURL" );
         String author = tip.getAttribute( "author" );

         // Append to the OL list of tips from the HashMap for this author:
         Node list = (Node) authors.get( author );
         Node item = list.appendChild( outputDoc.createElement( "LI" ) );

         // Each tip uses the title as the link text:
         Element link = outputDoc.createElement( "A" );
         item.appendChild( link );
         link.appendChild( outputDoc.createTextNode( title ) );
         link.setAttribute( "HREF", htmlURL );
      }
   }

   // This method builds (creates) an initial DOM for the output:
   public void createHTMLDoc ( String heading )
                    throws ParserConfigurationException  
   {
       DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
       DocumentBuilder db = dbf.newDocumentBuilder();  // Can these be reused?
       outputDoc = db.newDocument();
       html = outputDoc.createElement( "HTML" );
       outputDoc.appendChild( html );
       body = outputDoc.createElement( "BODY" );
       html.appendChild( body );
       Element h1 = outputDoc.createElement( "H1" );
       body.appendChild( h1 );
       h1.appendChild( outputDoc.createTextNode( heading ) );
   }

   // Prints the specified node, recursively.
   public void print ( Node node )
   {
      // is there anything to do?
      if ( node == null )
         return;

      int type = node.getNodeType();
      switch ( type )
      {
      case Node.DOCUMENT_NODE: {       // print document
         NodeList children = node.getChildNodes(); 
         for ( int iChild = 0; iChild < children.getLength(); ++iChild )
             print( children.item( iChild ) ); 
         break;
      }

      case Node.ELEMENT_NODE: {    // print element with attributes
         out.append( '<' );
         out.append( node.getNodeName() );
         Attr attrs[] = sortAttributes( node.getAttributes() );
         for ( int i = 0; i < attrs.length; ++i )
         {  Attr attr = attrs[i];
            out.append( ' ' );
            out.append( attr.getNodeName() );
            out.append( "=\"" );
            out.append( normalize( attr.getNodeValue() ) );
            out.append( '"' );
         }
         out.append( '>' );
         NodeList children = node.getChildNodes();
         if ( children != null )
         {  int len = children.getLength();
            for ( int i = 0; i < len; ++i )
            {  print(children.item(i));
            }
         }
         break;
      }

      case Node.ENTITY_REFERENCE_NODE: {  // handle entity reference nodes
         out.append( '&' );
         out.append( node.getNodeName() );
         out.append( ';' );
         break;
      }

      case Node.CDATA_SECTION_NODE: {      // print cdata sections
         out.append( "<![CDATA[" );
         out.append( node.getNodeValue() );
         out.append( "]]>" );
         break;
     }

     case Node.TEXT_NODE: {   // print text
        out.append( normalize( node.getNodeValue() ) );
        break;
     }

     case Node.PROCESSING_INSTRUCTION_NODE: {   // print processing instruction
        out.append( "<?" );
        out.append( node.getNodeName() );
        String data = node.getNodeValue();
        if ( data != null && data.length() > 0 )
        {  out.append( ' ' );
           out.append( data );
        }
        out.append( "?>\n" );  // on DOS systems should use "\r\n".
        break;
     }
     }  // End of switch

     if ( type == Node.ELEMENT_NODE )
     {  out.append( "</" );
        out.append( node.getNodeName() );
        out.append( '>' );
     }
     return;
   } // print(Node)


   // Returns a sorted list of attributes.  Note Java2 has an Array.sort method!
   protected Attr [] sortAttributes ( NamedNodeMap attrs )
   {
      int len = (attrs != null) ? attrs.getLength() : 0;
      Attr array[] = new Attr[len];
      for ( int i = 0; i < len; ++i )
      {  array[i] = (Attr)attrs.item(i);
      }
      for ( int i = 0; i < len - 1; ++i )
      {  String name  = array[i].getNodeName();
         int    index = i;
         for ( int j = i + 1; j < len; ++j )
         {  String curName = array[j].getNodeName();
            if ( curName.compareTo(name) < 0 )
            {   name  = curName;
                index = j;
            }
         }
         if ( index != i )
         {  Attr temp    = array[i];
            array[i]     = array[index];
            array[index] = temp;
         }
      }
      return ( array );
   } // sortAttributes(NamedNodeMap):Attr[]


    // Normalizes the given string.
    protected String normalize ( String s )
    {
       StringBuffer str = new StringBuffer();

       int len = (s != null) ? s.length() : 0;
       for ( int i = 0; i < len; ++i )
       {  char ch = s.charAt(i);
          switch ( ch )
          {
          case '<': {
             str.append("&lt;");
             break;
          }
          case '>': {
             str.append("&gt;");
             break;
          }
          case '&': {
             str.append("&amp;");
             break;
          }
          case '"': {
             str.append("&quot;");
             break;
          }
          case '\r': break;  // replace "\r\n" with "\n" (hopefully!?)
          case '\n':
          default: {
             str.append(ch);
          }
          }  // End of switch.
       }
       return(str.toString());
   } // normalize(String):String

    public static void main ( String [] args )
    {  try
       {  UseDOM ud = new UseDOM();
          ud.createHTMLDoc( "JDC Tech Tips Archive" );
          ud.processWithDOM( args[0] );
          String htmlOut = ud.toString();
          System.out.println( "Saving result to " + args[1] );
          FileWriter fw = new FileWriter( args[1] );
          fw.write( htmlOut, 0, htmlOut.length() );
          fw.flush();
       }
       catch ( Throwable t ) {  t.printStackTrace();  }
   }
}




Next TechTipArchive.xml Download this XML file



<?xml version="1.0" encoding="UTF-8"?>
<tips>
<author id="glen" fullName="Glen McCluskey"/>
<author id = "stu" fullName="Stuart Halloway"/>
<tip title="Random Access for Files"
     author="glen"
     htmlURL="http://developer.java.sun.com/developer/TechTips/2000/tt0509.html#tip1"
     textURL="http://developer.java.sun.com/developer/TechTips/txtarchive/May00_GlenM.txt">
</tip>
<tip title="Using Adapters"
     author="glen"
     htmlURL="http://developer.java.sun.com/developer/TechTips/2000/tt0509.html#tip2"
     textURL="http://developer.java.sun.com/developer/TechTips/txtarchive/May00_GlenM.txt">
</tip>
<tip title="Using Dynamic Proxies to Layer New Functionality Over Existing Code"
     author="stu"
     htmlURL="http://developer.java.sun.com/developer/TechTips/2000/tt0530.html#tip1"
     textURL="http://developer.java.sun.com/developer/TechTips/txtarchive/May00_Stu.txt">
</tip>
<tip title="Run Recurring or Future Tasks on a Background Thread"
     author="stu"
     htmlURL="http://developer.java.sun.com/developer/TechTips/2000/tt0530.html#tip2"
     textURL="http://developer.java.sun.com/developer/TechTips/txtarchive/May00_Stu.txt">
</tip>
</tips>




Back to Top ListTipsByAuthor.htm Download this HTML file
(HTML Output of: java UseDom TechTipArchive.xml ListTipsByAuthor.htm, slightly modified for readability)

JDC Tech Tips Archive

by Glen McCluskey

  1. Random Access for Files
  2. Using Adapters

by Stuart Halloway

  1. Using Dynamic Proxies to Layer New Functionality Over Existing Code
  2. Run Recurring or Future Tasks on a Background Thread


Send comments and mail to the WebMaster.