package at.ac.tuwien.dsg.scaledom.util; import org.apache.xerces.dom.ParentNode; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import at.ac.tuwien.dsg.scaledom.dom.ChildNodeList; /** * This utility class traverses a DOM tree, starting at a given root node (may also be the Document itself). For each * traversed node a callback method is called (visitor pattern). * * @author Dominik Rauch */ public class DOMTraverser { /** Determines whether the children should be traversed as well. */ private final boolean deep; /** Determines whether the children should be reloaded if currently not loaded. */ private final boolean eager; /** The callback interface. */ private final DOMTraverserCallback callback; /** * Calls this(true, true, callback). * * @see #DOMTraverser(boolean, boolean, DOMTraverserCallback) */ public DOMTraverser(final DOMTraverserCallback callback) { this(true, true, callback); } /** * Default constructor. * * @param deep true if the children should be traversed as well, otherwise false. * @param eager true if children should be reloaded if currently not loaded. * @param callback the callback interface, which is called for each traversed node. */ public DOMTraverser(final boolean deep, final boolean eager, final DOMTraverserCallback callback) { this.deep = deep; this.eager = eager; this.callback = callback; } /** * Starts the traversal at the given node. * * @param node root node for this traversal. */ public void traverse(final Node node) { traverseInternal(node.getOwnerDocument(), node, 0); } private void traverseInternal(final Document doc, final Node node, final int level) { callback.nodeTraversed(doc, node, level); if (deep && node instanceof ParentNode) { // Get child nodes final ParentNode nodeAsParent = (ParentNode) node; final NodeList childNodes; if (eager) { childNodes = nodeAsParent.getChildNodes(); } else { childNodes = new ChildNodeList(nodeAsParent.getLoadedChildNodes()); } // Traverse child nodes for (int i = 0; i < childNodes.getLength(); ++i) { final Node childNode = childNodes.item(i); traverseInternal(doc, childNode, level + 1); } } } }