All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.xerces.dom.NodeIteratorImpl Maven / Gradle / Ivy

There is a newer version: 6.2.20
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.xerces.dom;

import org.w3c.dom.DOMException;
import org.w3c.dom.Node;
import org.w3c.dom.traversal.NodeFilter;
import org.w3c.dom.traversal.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 $ */ public class NodeIteratorImpl implements NodeIterator { // // Data // /** The DocumentImpl which created this iterator, so it can be detached. */ private DocumentImpl fDocument; /** The root. */ private Node fRoot; /** The whatToShow mask. */ private int fWhatToShow = NodeFilter.SHOW_ALL; /** The NodeFilter reference. */ private NodeFilter fNodeFilter; /** If detach is called, the fDetach flag is true, otherwise flase. */ private boolean fDetach = false; // // Iterator state - current node and direction. // // Note: The current node and direction are sufficient to implement // the desired behaviour of the current pointer being _between_ // two nodes. The fCurrentNode is actually the last node returned, // and the // direction is whether the pointer is in front or behind this node. // (usually akin to whether the node was returned via nextNode()) // (eg fForward = true) or previousNode() (eg fForward = false). // Note also, if removing a Node, the fCurrentNode // can be placed on a Node which would not pass filters. /** The last Node returned. */ private Node fCurrentNode; /** The direction of the iterator on the fCurrentNode. *

     *  nextNode()  ==      fForward = true;
     *  previousNode() ==   fForward = false;
     *  
*/ private boolean fForward = true; /** When TRUE, the children of entites references are returned in the iterator. */ private boolean fEntityReferenceExpansion; // // Constructor // /** Public constructor */ public NodeIteratorImpl( DocumentImpl document, Node root, int whatToShow, NodeFilter nodeFilter, boolean entityReferenceExpansion) { fDocument = document; fRoot = root; fCurrentNode = null; fWhatToShow = whatToShow; fNodeFilter = nodeFilter; fEntityReferenceExpansion = entityReferenceExpansion; } public Node getRoot() { return fRoot; } // Implementation Note: Note that the iterator looks at whatToShow // and filter values at each call, and therefore one _could_ add // setters for these values and alter them while iterating! /** Return the whatToShow value */ public int getWhatToShow() { return fWhatToShow; } /** Return the filter */ public NodeFilter getFilter() { return fNodeFilter; } /** Return whether children entity references are included in the iterator. */ public boolean getExpandEntityReferences() { return fEntityReferenceExpansion; } /** 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. */ public Node nextNode() { 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; } /** 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. */ public Node previousNode() { 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; } /** The node is accepted if it passes the whatToShow and the filter. */ boolean acceptNode(Node node) { if (fNodeFilter == null) { return ( fWhatToShow & (1 << node.getNodeType()-1)) != 0 ; } else { return ((fWhatToShow & (1 << node.getNodeType()-1)) != 0 ) && fNodeFilter.acceptNode(node) == NodeFilter.FILTER_ACCEPT; } } /** Return node, if matches or any parent if matches. */ Node matchNodeOrParent(Node node) { // 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; } /** 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. */ Node nextNode(Node node, boolean visitChildren) { 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; } /** The method previousNode(Node) returns the previous node * from the actual DOM tree. */ Node previousNode(Node node) { 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; } /** Fix-up the iterator on a remove. Called by DOM or otherwise, * before an actual DOM remove. */ public void removeNode(Node node) { // 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; } } } public void detach() { fDetach = true; fDocument.removeNodeIterator(this); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy