FileDocCategorySizeDatePackage
NodeIteratorImpl.javaAPI DocApache Xerces 3.0.113163Fri Sep 14 20:33:54 BST 2007org.apache.xerces.dom

NodeIteratorImpl

public class NodeIteratorImpl extends Object implements NodeIterator
DefaultNodeIterator implements a NodeIterator, which iterates a DOM tree in the expected depth first way.

The whatToShow and filter functionality is implemented as expected.

This class also has method removeNode to enable iterator "fix-up" on DOM remove. It is expected that the DOM implementation call removeNode right before the actual DOM transformation. If not called by the DOM, the client could call it before doing the removal.

xerces.internal
version
$Id: NodeIteratorImpl.java 447266 2006-09-18 05:57:49Z mrglavas $

Fields Summary
private DocumentImpl
fDocument
The DocumentImpl which created this iterator, so it can be detached.
private Node
fRoot
The root.
private int
fWhatToShow
The whatToShow mask.
private NodeFilter
fNodeFilter
The NodeFilter reference.
private boolean
fDetach
If detach is called, the fDetach flag is true, otherwise flase.
private Node
fCurrentNode
The last Node returned.
private boolean
fForward
The direction of the iterator on the fCurrentNode.
nextNode() == fForward = true;
previousNode() == fForward = false;
private boolean
fEntityReferenceExpansion
When TRUE, the children of entites references are returned in the iterator.
Constructors Summary
public NodeIteratorImpl(DocumentImpl document, Node root, int whatToShow, NodeFilter nodeFilter, boolean entityReferenceExpansion)
Public constructor

    
    // 
    // Constructor
    //
    
       
       
                               
                               
                              
                               
        fDocument = document;
        fRoot = root;
        fCurrentNode = null;
        fWhatToShow = whatToShow;
        fNodeFilter = nodeFilter;
        fEntityReferenceExpansion = entityReferenceExpansion;
    
Methods Summary
booleanacceptNode(org.w3c.dom.Node node)
The node is accepted if it passes the whatToShow and the filter.

                
        if (fNodeFilter == null) {            
            return ( fWhatToShow & (1 << node.getNodeType()-1)) != 0 ;
        } else {
            return ((fWhatToShow & (1 << node.getNodeType()-1)) != 0 ) 
                && fNodeFilter.acceptNode(node) == NodeFilter.FILTER_ACCEPT;
        }
    
public voiddetach()

        fDetach = true;
        fDocument.removeNodeIterator(this);
    
public booleangetExpandEntityReferences()
Return whether children entity references are included in the iterator.

        return fEntityReferenceExpansion;
    
public org.w3c.dom.traversal.NodeFiltergetFilter()
Return the filter

        return fNodeFilter;
    
public org.w3c.dom.NodegetRoot()

	return fRoot;
    
public intgetWhatToShow()
Return the whatToShow value

        return fWhatToShow;
    
org.w3c.dom.NodematchNodeOrParent(org.w3c.dom.Node node)
Return node, if matches or any parent if matches.

        // Additions and removals in the underlying data structure may occur
        // before any iterations, and in this case the reference_node is null.
        if (fCurrentNode == null) return null;
        
        // check if the removed node is an _ancestor_ of the 
        // reference node
        for (Node n = fCurrentNode; n != fRoot; n = n.getParentNode()) {
            if (node == n) return n;
        }
        return null;
    
org.w3c.dom.NodenextNode(org.w3c.dom.Node node, boolean visitChildren)
The method nextNode(Node, boolean) returns the next node from the actual DOM tree. The boolean visitChildren determines whether to visit the children. The result is the nextNode.

            
        if (node == null) return fRoot;

        Node result;
        // only check children if we visit children.
        if (visitChildren) {
            //if hasChildren, return 1st child.
            if (node.hasChildNodes()) {
                result = node.getFirstChild();
                return result;
            }
        }
            
        if (node == fRoot) { //if Root has no kids
            return null;
        }

        // if hasSibling, return sibling
        result = node.getNextSibling();
        if (result != null) return result;
        
                
        // return parent's 1st sibling.
        Node parent = node.getParentNode();
        while (parent != null && parent != fRoot) {
            result = parent.getNextSibling();
            if (result != null) {
                return result;
            } else {
                parent = parent.getParentNode();
            }
                            
        } // while (parent != null && parent != fRoot) {
        
        // end of list, return null
        return null;            
    
public org.w3c.dom.NodenextNode()
Return the next Node in the Iterator. The node is the next node in depth-first order which also passes the filter, and whatToShow. If there is no next node which passes these criteria, then return null.

        
    	if( fDetach) {
    		throw new DOMException(
    		DOMException.INVALID_STATE_ERR, 
                DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null));
        }
        
        // if root is null there is no next node.
        if (fRoot == null) return null;
        
        Node nextNode = fCurrentNode;
        boolean accepted = false; // the next node has not been accepted.
     
        accepted_loop:
        while (!accepted) {
            
            // if last direction is not forward, repeat node.
            if (!fForward && nextNode!=null) {
                //System.out.println("nextNode():!fForward:"+fCurrentNode.getNodeName());
                nextNode = fCurrentNode;
            } else { 
            // else get the next node via depth-first
                if (!fEntityReferenceExpansion
                    && nextNode != null
                    && nextNode.getNodeType() == Node.ENTITY_REFERENCE_NODE) {
                    nextNode = nextNode(nextNode, false);
                } else {
                    nextNode = nextNode(nextNode, true);
                }
            }
   
            fForward = true; //REVIST: should direction be set forward before null check?
            
            // nothing in the list. return null.
            if (nextNode == null) return null; 
            
            // does node pass the filters and whatToShow?
            accepted = acceptNode(nextNode);
            if (accepted) {
                // if so, then the node is the current node.
                fCurrentNode = nextNode;
                return fCurrentNode;
            } else 
                continue accepted_loop;
            
        } // while (!accepted) {
        
        // no nodes, or no accepted nodes.
        return null;
            
    
org.w3c.dom.NodepreviousNode(org.w3c.dom.Node node)
The method previousNode(Node) returns the previous node from the actual DOM tree.

        
        Node result;
        
        // if we're at the root, return null.
        if (node == fRoot) return null;
        
        // get sibling
        result = node.getPreviousSibling();
        if (result == null) {
            //if 1st sibling, return parent
            result = node.getParentNode();
            return result;
        }
        
        // if sibling has children, keep getting last child of child.
        if (result.hasChildNodes()
            && !(!fEntityReferenceExpansion
                && result != null
                && result.getNodeType() == Node.ENTITY_REFERENCE_NODE)) 
       
        {
            while (result.hasChildNodes()) {
                result = result.getLastChild();
            }
        }          
            
        return result;
    
public org.w3c.dom.NodepreviousNode()
Return the previous Node in the Iterator. The node is the next node in _backwards_ depth-first order which also passes the filter, and whatToShow.

        
    	if( fDetach) {
    		throw new DOMException(
    		DOMException.INVALID_STATE_ERR, 
                DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null));
        }
 
        // if the root is null, or the current node is null, return null.
        if (fRoot == null || fCurrentNode == null) return null;
       
        Node previousNode = fCurrentNode;
        boolean accepted = false;
        
        accepted_loop:
        while (!accepted) {
            
            if (fForward && previousNode != null) {
                //repeat last node.
                previousNode = fCurrentNode;
            } else { 
                // get previous node in backwards depth first order.
                previousNode = previousNode(previousNode);
            }
            
            // we are going backwards
            fForward = false;
            
            // if the new previous node is null, we're at head or past the root,
            // so return null. 
            if (previousNode == null) return null;
            
            // check if node passes filters and whatToShow.
            accepted = acceptNode(previousNode);
            if (accepted) {
                // if accepted, update the current node, and return it.
                fCurrentNode = previousNode;
                return fCurrentNode;
            } else 
                continue accepted_loop;
        }
        // there are no nodes?
        return null;
    
public voidremoveNode(org.w3c.dom.Node node)
Fix-up the iterator on a remove. Called by DOM or otherwise, before an actual DOM remove.

        
        // Implementation note: Fix-up means setting the current node properly
        // after a remove.
        
        if (node == null) return;
        
        Node deleted = matchNodeOrParent(node);
        
        if (deleted == null) return;
        
        if (fForward) {
            fCurrentNode = previousNode(deleted);
        } else
        // if (!fForward) 
        {
            Node next = nextNode(deleted, false);
            if (next!=null) {
                // normal case: there _are_ nodes following this in the iterator.
                fCurrentNode = next;
            } else {
                // the last node in the iterator is to be removed, 
                // so we set the current node to be the previous one.
                fCurrentNode = previousNode(deleted);
                fForward = true;
            }
                
        }