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

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

Go to download

Xerces2 is the next generation of high performance, fully compliant XML parsers in the Apache Xerces family. This new version of Xerces introduces the Xerces Native Interface (XNI), a complete framework for building parser components and configurations that is extremely modular and easy to program. The Apache Xerces2 parser is the reference implementation of XNI but other parser components, configurations, and parsers can be written using the Xerces Native Interface. For complete design and implementation documents, refer to the XNI Manual. Xerces2 is a fully conforming XML Schema 1.0 processor. A partial experimental implementation of the XML Schema 1.1 Structures and Datatypes Working Drafts (December 2009) and an experimental implementation of the XML Schema Definition Language (XSD): Component Designators (SCD) Candidate Recommendation (January 2010) are provided for evaluation. For more information, refer to the XML Schema page. Xerces2 also provides a complete implementation of the Document Object Model Level 3 Core and Load/Save W3C Recommendations and provides a complete implementation of the XML Inclusions (XInclude) W3C Recommendation. It also provides support for OASIS XML Catalogs v1.1. Xerces2 is able to parse documents written according to the XML 1.1 Recommendation, except that it does not yet provide an option to enable normalization checking as described in section 2.13 of this specification. It also handles namespaces according to the XML Namespaces 1.1 Recommendation, and will correctly serialize XML 1.1 documents if the DOM level 3 load/save APIs are in use.

There is a newer version: 2.12.2
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