When a pass or two through the document isn't enough for your program, you may need to build a tree representation of the document to keep it in memory until processing is done. If event-based processing represents serial access to XML, then tree-based processing represents random access. Your program can jump around in the document, since it's now liberated from the linear, single-pass path.
The program in Example 8.2 extends the parser from Example 8.1 to build a tree data structure. After the tree is built, a processing routine traverses it, node by node, applying rules to modify it. This version is called dbfix.
Traversing a tree is not difficult. For each node, if there are children (a nonempty element, for example), you process each child of the node, repeat for the children of the children, and so on, until you reach the leaves of the tree. This process is called recursion, and its hallmark is a routine that calls itself. The subroutine process_tree() is recursive, because it calls itself for each of the children of a nonempty element. The routine that outputs the tree to a file, serialize_tree(), also uses recursion in that way.
This program performs a set of transformations on elements, encoded in rules. The hash table %unwrap_element contains rules for "unwrapping" elements in certain contexts. To unwrap an element is to delete the start and end tags, leaving the content in place. The unwrapping ...