Walking DOM Trees

The visitor concept described here is similar to the visitor of the Visitor Design Pattern.

A visitor walks through a DOM tree visiting every node.

Depending on the type of the node, the visitor calls a specialized visit method for processing that type of node.

For example:

   protected void visit(Element node) throws VisitorException { }
   protected void visit(Text node) throws VisitorException { }
   protected void visit(Attr node) throws VisitorException { }

Although these methods have empty implementations, they can be overridden in visitor subclasses.

The node visitor identifies the type of the node, then dispatches to one of these more specialized visitors:

   public void visit(Node node) throws VisitorException {
      // temporarily store node details:
      name = node.getNodeName();
      value = node.getNodeValue();
      if (value != null) value = value.trim();
      // dispatch to specialized visitor:
      switch (node.getNodeType()) {
         case Node.ELEMENT_NODE:
            Element elem = (Element) node;
            visit(elem);
            visit(node.getAttributes());
            visit(node.getChildNodes());
            break;
         case Node.ATTRIBUTE_NODE:
            Attr attr = (Attr) node;
            visit(attr);
            break;
         case Node.CDATA_SECTION_NODE:
         case Node.TEXT_NODE:
            Text text = (Text) node;
            visit(text);
            break;
      } // switch
   } // visit node

We can customize our visitor by overriding the overridables in extensions of the Visitor class:

Implementation

Visitor.java

VisitorException.java

PrettyPrintVisitor.java

SearchVisitor.java

Demonstration

OrgML is an XML language for representing the members of an organization and their dependants.

Here's a nicely formatted version of an OrgML file representing a mythical organization:

org0.xml

Here's the same version but with the formatting removed (this will be easier for our simple programs to process):

org1.xml

The following file contains an implementation of a search visitor that finds all of the dependants of a member given the member's ID:

SponsorSearchVisitor.java

Here's the design:

Our test driver first uses a sponsor search visitor to generate a list of all dependants having Homer as their sponsor, then visits each element in this list with a pretty print visitor:

TestVisitor.java

Here's the output produced:

dependants sponsored by Homer:
Element node: dependant
.(Attribute node: gender = female)
.(Attribute node: id = p2)
.Element node: lastName
..Text node:   Simpson
.Element node: firstName
..Text node:   Marge
.Element node: dob
..Text node:   1955-10-20
.Element node: sponsor
..(Attribute node: id = p1)
Element node: dependant
.(Attribute node: gender = female)
.(Attribute node: id = p3)
.Element node: lastName
..Text node:   Simpson
.Element node: firstName
..Text node:   Lisa
.Element node: dob
..Text node:   1985-06-22
.Element node: sponsor
..(Attribute node: id = p1)
Element node: dependant
.(Attribute node: gender = female)
.(Attribute node: id = p4)
.Element node: lastName
..Text node:   Simpson
.Element node: firstName
..Text node:   Maggie
.Element node: dob
..Text node:   1988-11-11
.Element node: sponsor
..(Attribute node: id = p1)
Element node: dependant
.(Attribute node: gender = male)
.(Attribute node: id = p5)
.Element node: lastName
..Text node:   Simpson
.Element node: firstName
..Text node:   Bart
.Element node: dob
..Text node:   1983-01-01
.Element node: sponsor
..(Attribute node: id = p1)