/* * 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. */ /* * $Id$ */ ////////////////////////////////////////////////////////////////////// // DOMNodeIteratorImpl.cpp: implementation of the DOMNodeIteratorImpl class. // ////////////////////////////////////////////////////////////////////// #include "DOMNodeIteratorImpl.hpp" #include "DOMDocumentImpl.hpp" #include #include XERCES_CPP_NAMESPACE_BEGIN ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// DOMNodeIteratorImpl::DOMNodeIteratorImpl (DOMDocument* doc, DOMNode* root, DOMNodeFilter::ShowType whatToShow, DOMNodeFilter* nodeFilter, bool expandEntityRef) : fRoot(root), fDocument(doc), fWhatToShow(whatToShow), fNodeFilter(nodeFilter), fExpandEntityReferences(expandEntityRef), fDetached(false), fCurrentNode(0), fForward(true) { } DOMNodeIteratorImpl::DOMNodeIteratorImpl ( const DOMNodeIteratorImpl& toCopy) : DOMNodeIterator(toCopy), fRoot(toCopy.fRoot), fDocument(toCopy.fDocument), fWhatToShow(toCopy.fWhatToShow), fNodeFilter(toCopy.fNodeFilter), fExpandEntityReferences(toCopy.fExpandEntityReferences), fDetached(toCopy.fDetached), fCurrentNode(toCopy.fCurrentNode), fForward(toCopy.fForward) { } DOMNodeIteratorImpl& DOMNodeIteratorImpl::operator= (const DOMNodeIteratorImpl& other) { fRoot = other.fRoot; fCurrentNode = other.fRoot; fWhatToShow = other.fWhatToShow; fNodeFilter = other.fNodeFilter; fForward = other.fForward; fDetached = other.fDetached; fExpandEntityReferences = other.fExpandEntityReferences; fDocument = other.fDocument; return *this; } DOMNodeIteratorImpl::~DOMNodeIteratorImpl () { fDetached = false; } void DOMNodeIteratorImpl::detach () { fDetached = true; ((DOMDocumentImpl *)fDocument)->removeNodeIterator(this); } DOMNode* DOMNodeIteratorImpl::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 */ DOMNodeFilter::ShowType DOMNodeIteratorImpl::getWhatToShow () { return fWhatToShow; } /** Return the filter */ DOMNodeFilter* DOMNodeIteratorImpl::getFilter () { return fNodeFilter; } /** Get the expandEntity reference flag. */ bool DOMNodeIteratorImpl::getExpandEntityReferences() { return fExpandEntityReferences; } /** Return the next DOMNode* in the Iterator. The node is the next node in * depth-first order which also passes the filter, and whatToShow. * A 0 return means either that */ DOMNode* DOMNodeIteratorImpl::nextNode () { if (fDetached) throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager); // if root is 0 there is no next node-> if (!fRoot) return 0; DOMNode* aNextNode = fCurrentNode; bool accepted = false; // the next node has not been accepted. while (!accepted) { // if last direction is not forward, repeat node-> if (!fForward && (aNextNode != 0)) { //System.out.println("nextNode():!fForward:"+fCurrentNode.getNodeName()); aNextNode = fCurrentNode; } else { // else get the next node via depth-first aNextNode = nextNode(aNextNode, true); } fForward = true; //REVIST: should direction be set forward before 0 check? // nothing in the list. return 0. if (!aNextNode) return 0; // does node pass the filters and whatToShow? accepted = acceptNode(aNextNode); if (accepted) { // if so, then the node is the current node-> fCurrentNode = aNextNode; return fCurrentNode; } } // no nodes, or no accepted nodes. return 0; } /** 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. */ DOMNode* DOMNodeIteratorImpl::previousNode () { if (fDetached) throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager); // if the root is 0, or the current node is 0, return 0. if (!fRoot || !fCurrentNode) return 0; DOMNode* aPreviousNode = fCurrentNode; bool accepted = false; while (!accepted) { if (fForward && (aPreviousNode != 0)) { //repeat last node-> aPreviousNode = fCurrentNode; } else { // get previous node in backwards depth first order. aPreviousNode = previousNode(aPreviousNode); } // we are going backwards fForward = false; // if the new previous node is 0, we're at head or past the root, // so return 0. if (!aPreviousNode) return 0; // check if node passes filters and whatToShow. accepted = acceptNode(aPreviousNode); if (accepted) { // if accepted, update the current node, and return it. fCurrentNode = aPreviousNode; return fCurrentNode; } } // there are no nodes? return 0; } /** The node is accepted if it passes the whatToShow and the filter. */ bool DOMNodeIteratorImpl::acceptNode (DOMNode* node) { if (fDetached) throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager); if (fNodeFilter == 0) { return ((fWhatToShow & (1 << (node->getNodeType() - 1))) != 0); } else { return ((fWhatToShow & (1 << (node->getNodeType() - 1))) != 0) && fNodeFilter->acceptNode(node) == DOMNodeFilter::FILTER_ACCEPT; } } /** Return node, if matches or any parent if matches. */ DOMNode* DOMNodeIteratorImpl::matchNodeOrParent (DOMNode* node) { for (DOMNode* n = fCurrentNode; n != fRoot; n = n->getParentNode()) { if (node == n) return n; } return 0; } /** The method nextNode(DOMNode, bool) returns the next node * from the actual DOM tree. * * The bool visitChildren determines whether to visit the children. * The result is the nextNode. */ DOMNode* DOMNodeIteratorImpl::nextNode (DOMNode* node, bool visitChildren) { if (fDetached) throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager); if (!node) return fRoot; DOMNode* result = 0; // only check children if we visit children. if (visitChildren) { //if hasChildren, return 1st child. if ((fExpandEntityReferences || node->getNodeType()!=DOMNode::ENTITY_REFERENCE_NODE) && node->hasChildNodes()) { result = node->getFirstChild(); return result; } } // if hasSibling, return sibling if (node != fRoot) { result = node->getNextSibling(); if (result != 0) return result; // return parent's 1st sibling. DOMNode* parent = node->getParentNode(); while ((parent != 0) && parent != fRoot) { result = parent->getNextSibling(); if (result != 0) { return result; } else { parent = parent->getParentNode(); } } // while (parent != 0 && parent != fRoot) { } // end of list, return 0 return 0; } /** The method previousNode(DOMNode) returns the previous node * from the actual DOM tree. */ DOMNode* DOMNodeIteratorImpl::previousNode (DOMNode* node) { if (fDetached) throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager); DOMNode* result = 0; // if we're at the root, return 0. if (node == fRoot) return 0; // get sibling result = node->getPreviousSibling(); if (!result) { //if 1st sibling, return parent result = node->getParentNode(); return result; } // if sibling has children, keep getting last child of child. if (result->hasChildNodes()) { while ((fExpandEntityReferences || result->getNodeType()!=DOMNode::ENTITY_REFERENCE_NODE) && result->hasChildNodes()) { result = result->getLastChild(); } } return result; } /** Fix-up the iterator on a remove. Called by DOM or otherwise, * before an actual DOM remove. */ void DOMNodeIteratorImpl::removeNode (DOMNode* node) { if (fDetached) throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager); // Implementation note: Fix-up means setting the current node properly // after a remove. if (!node) return; DOMNode* deleted = matchNodeOrParent(node); if (!deleted) return; if (fForward) { fCurrentNode = previousNode(deleted); } else // if (!fForward) { DOMNode* next = nextNode(deleted, false); if (next != 0) { // 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; } } } void DOMNodeIteratorImpl::release() { detach(); // for performance reason, do not recycle pointer // chance that this is allocated again and again is not usual } XERCES_CPP_NAMESPACE_END