
org.enhydra.xml.dom.DOMTraversal Maven / Gradle / Ivy
/*
* Enhydra Java Application Server Project
*
* The contents of this file are subject to the Enhydra Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License on
* the Enhydra web site ( http://www.enhydra.org/ ).
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific terms governing rights and limitations
* under the License.
*
* The Initial Developer of the Enhydra Application Server is Lutris
* Technologies, Inc. The Enhydra Application Server and portions created
* by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
* All Rights Reserved.
*
* Contributor(s):
*
* $Id: DOMTraversal.java,v 1.2 2005/01/26 08:29:24 jkjome Exp $
*/
package org.enhydra.xml.dom;
import java.util.Iterator;
import java.util.TreeMap;
import org.enhydra.xml.lazydom.LazyDOMTraversal;
import org.w3c.dom.Attr;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.Entity;
import org.w3c.dom.EntityReference;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.Notation;
import org.w3c.dom.ProcessingInstruction;
import org.w3c.dom.Text;
/**
* Class that traverse a DOM tree or subtree, calling handler methods for
* each node. It is up to the handler methods to make a decision on
* processing child and element nodes by explictly calling the methods
* to continue the traversal. This is gives the handler more control and
* actually kept the code simpler for both this class and the client.
*
* While DOM traversal is straight-forward, traversing the LazyDOM while
* avoiding expansion made things tricker. This class, and the derived class
* for the LazyDOM, handles these special cases.
*/
public class DOMTraversal {
/**
* Option flag to indicate that attributes should be sorted before calling
* the handlers.
*/
public static final int SORT_ATTRIBUTES = 0x01;
/**
* Option flag to indicate that unspecified attributes should be included.
*/
public static final int ALL_ATTRIBUTES = 0x02;
/**
* Interface for node callback object.
*/
public interface Handler {
/**
* Handler called for Document nodes.
* Call processDocumentType to traverse child nodes.
* Call processChildren to traverse child nodes.
*/
public void handleDocument(Document document) throws Exception;
/**
* Handler called for DocumentType nodes.
* Use processDocumentTypeContents to traverse contain nodes.
*/
public void handleDocumentType(DocumentType documentType) throws Exception;
/**
* Handler called for DocumentFragment nodes.
* Call processChildren to traverse child nodes.
*/
public void handleDocumentFragment(DocumentFragment documentFragment) throws Exception;
/**
* Handler called for Attr nodes.
* Call processChildren to traverse child nodes.
*/
public void handleAttr(Attr attr) throws Exception;
/**
* Handler called for Entity nodes.
* Call processChildren to traverse child nodes.
*/
public void handleEntity(Entity entity) throws Exception;
/**
* Handler called for EntityReference nodes.
* Call processChildren to traverse child nodes.
*/
public void handleEntityReference(EntityReference entityRef) throws Exception;
/**
* Handler called for Element nodes.
* Call processChildren to traverse child nodes.
* Call processAttributes to traverse attribute nodes.
*/
public void handleElement(Element element) throws Exception;
/**
* Handler called for Notation nodes.
*/
public void handleNotation(Notation notation) throws Exception;
/**
* Handler called for ProcessingInstruction nodes.
*/
public void handleProcessingInstruction(ProcessingInstruction pi) throws Exception;
/**
* Handler called for CDATASection nodes.
*/
public void handleCDATASection(CDATASection cdata) throws Exception;
/**
* Handler called for Comment nodes.
*/
public void handleComment(Comment comment) throws Exception;
/**
* Handler called for Text nodes.
*/
public void handleText(Text text) throws Exception;
}
/**
* Implementation of handler that calls a single method for
* all node types.
*/
abstract public class NodeHandler implements Handler {
/**
* Method that is called for all nodes.
*/
abstract public void handleNode(Node node) throws Exception;
/**
* All standrd handler methods.
*/
public void handleDocument(Document document) throws Exception {
handleNode(document);
}
public void handleDocumentType(DocumentType documentType) throws Exception {
handleNode(documentType);
}
public void handleDocumentFragment(DocumentFragment documentFragment) throws Exception {
handleNode(documentFragment);
}
public void handleAttr(Attr attr) throws Exception {
handleNode(attr);
}
public void handleEntity(Entity entity) throws Exception {
handleNode(entity);
}
public void handleEntityReference(EntityReference entityRef) throws Exception {
handleNode(entityRef);
}
public void handleElement(Element element) throws Exception {
handleNode(element);
}
public void handleNotation(Notation notation) throws Exception {
handleNode(notation);
}
public void handleProcessingInstruction(ProcessingInstruction pi) throws Exception {
handleNode(pi);
}
public void handleCDATASection(CDATASection cdata) throws Exception {
handleNode(cdata);
}
public void handleComment(Comment comment) throws Exception {
handleNode(comment);
}
public void handleText(Text text) throws Exception {
handleNode(text);
}
}
/** Handler object for the traversal */
protected Handler fHandler;
/** Options controlling the traversal. */
protected int fOptions;
/** Current traversal tree depth */
protected int fDepth;
/** Are we processing an attribute or its children? */
protected boolean fProcessingAttribute;
/**
* Constructor.
* @param handler The object that will be called to handle each
* node.
* @param options Bit set of the option flags.
*/
public DOMTraversal(DOMTraversal.Handler handler,
int options) {
fHandler = handler;
fOptions = options;
}
/**
* Default constructor, set handler later.
*/
public DOMTraversal(int options) {
fOptions = options;
}
/**
* Set the handler.
*/
public void setHandler(DOMTraversal.Handler handler) {
fHandler = handler;
}
/**
* Traverse a DOM tree or subtree.
*
* @param root The root of the DOM tree or subtree that is to
* be traversed.
* @exception DOMError Any internal exceptions are encapsulated
* in this error.
*/
public void traverse(Node root) {
fDepth = 0;
fProcessingAttribute = false;
// Don't let XMLObject cause confusion
processNode(DOMOps.getActualNode(root));
}
/**
* Get the current depth in the DOM tree that is being traversed.
*/
public final int getDepth() {
return fDepth;
}
/**
* Are we currently processing an attribute node or its descendents?
*/
public final boolean processingAttribute() {
return fProcessingAttribute;
}
/**
* Process the children of a node.
*/
public void processChildren(Node node) {
fDepth++;
for (Node child = node.getFirstChild(); child != null;
child = child.getNextSibling()) {
if (!(child instanceof DocumentType)) {
processNode(child);
}
}
fDepth--;
}
/**
* Process the attributes of an element.
*/
public void processAttributes(Element element) {
NamedNodeMap attrMap = element.getAttributes();
if (attrMap != null) {
fDepth++;
if ((fOptions & SORT_ATTRIBUTES) != 0) {
processAttrsSorted(attrMap);
} else {
processAttrsUnsorted(attrMap);
}
fDepth--;
}
}
/**
* Process a DocumentType attribute of a Document node, if it exists.
*/
public void processDocumentType(Document document) {
DocumentType docType = document.getDoctype();
if (docType != null) {
processNode(docType);
}
}
/**
* Process the contents of a DocumentType node,
*/
public void processDocumentTypeContents(DocumentType documentType) {
processNamedNodeMap(documentType.getEntities());
processNamedNodeMap(documentType.getNotations());
}
/**
* Process attributes, sorted by name.
*/
private void processAttrsSorted(NamedNodeMap attrMap) {
// Build sorted list
int len = attrMap.getLength();
TreeMap map = new TreeMap();
for (int i = 0; i < len; i++) {
Node node = attrMap.item(i);
map.put(node.getNodeName(), node);
}
// Process attributes
Iterator attrs = map.values().iterator();
while (attrs.hasNext()) {
processNode((Node)attrs.next());
}
}
/**
* Process attributes in the order that they occur.
*/
private void processAttrsUnsorted(NamedNodeMap attrMap) {
int len = attrMap.getLength();
for (int i = 0; i < len; i++) {
processNode(attrMap.item(i));
}
}
/**
* Process contents of a NamedNodeMap.
*/
private void processNamedNodeMap(NamedNodeMap nodeMap) {
if (nodeMap != null) {
fDepth++;
int len = nodeMap.getLength();
for (int i = 0; i < len; i++) {
processNode(nodeMap.item(i));
}
fDepth--;
}
}
/**
* Processing based on node type. All nodes go through here.
*/
protected void processNode(Node node) {
try {
switch (node.getNodeType()) {
case Node.DOCUMENT_NODE:
fHandler.handleDocument((Document)node);
break;
case Node.DOCUMENT_TYPE_NODE:
fHandler.handleDocumentType((DocumentType)node);
break;
case Node.DOCUMENT_FRAGMENT_NODE:
fHandler.handleDocumentFragment((DocumentFragment)node);
break;
case Node.ATTRIBUTE_NODE:
processAttr((Attr)node);
break;
case Node.ELEMENT_NODE:
fHandler.handleElement((Element)node);
break;
case Node.ENTITY_NODE:
fHandler.handleEntity((Entity)node);
break;
case Node.ENTITY_REFERENCE_NODE:
fHandler.handleEntityReference((EntityReference)node);
break;
case Node.NOTATION_NODE:
fHandler.handleNotation((Notation)node);
break;
case Node.PROCESSING_INSTRUCTION_NODE:
fHandler.handleProcessingInstruction((ProcessingInstruction)node);
break;
case Node.TEXT_NODE:
fHandler.handleText((Text)node);
break;
case Node.CDATA_SECTION_NODE:
fHandler.handleCDATASection((CDATASection)node);
break;
case Node.COMMENT_NODE:
fHandler.handleComment((Comment)node);
break;
default:
throw new DOMError("unknown node type: " + node.getNodeType());
}
} catch (RuntimeException except) {
// Just Exception catch from getting 'em
throw except;
} catch (Exception except) {
throw new DOMError(except);
}
}
/**
* Process an Attr node.
*/
private void processAttr(Attr attr) throws Exception {
if (((fOptions & ALL_ATTRIBUTES) != 0) || attr.getSpecified()) {
fProcessingAttribute = true;
fHandler.handleAttr(attr);
fProcessingAttribute = false;
}
}
/**
* Factory method to create a traverser based on the type of
* a document.
*/
public static DOMTraversal getTraverser(Handler handler,
int options,
Node node) {
/*
* Find the document to determine type. The LazyDOM traverser is only
* used on instance documents. If a template DOM node is specified,
* the template LazyDocument is traverse as any other done.
*/
if (DOMOps.isLazyDOMInstance(DOMOps.getDocument(node))) {
return new LazyDOMTraversal(handler, options);
} else {
return new DOMTraversal(handler, options);
}
}
}