GME  13
DOMNodeIteratorImpl.cpp
Go to the documentation of this file.
00001 /*
00002  * Licensed to the Apache Software Foundation (ASF) under one or more
00003  * contributor license agreements.  See the NOTICE file distributed with
00004  * this work for additional information regarding copyright ownership.
00005  * The ASF licenses this file to You under the Apache License, Version 2.0
00006  * (the "License"); you may not use this file except in compliance with
00007  * the License.  You may obtain a copy of the License at
00008  *
00009  *      http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 /*
00019  * $Id: DOMNodeIteratorImpl.cpp 671894 2008-06-26 13:29:21Z borisk $
00020  */
00021 
00023 // DOMNodeIteratorImpl.cpp: implementation of the DOMNodeIteratorImpl class.
00024 //
00026 
00027 #include "DOMNodeIteratorImpl.hpp"
00028 #include "DOMDocumentImpl.hpp"
00029 #include <xercesc/dom/DOMDocument.hpp>
00030 #include <xercesc/dom/DOMException.hpp>
00031 
00032 XERCES_CPP_NAMESPACE_BEGIN
00033 
00035 // Construction/Destruction
00037 
00038 DOMNodeIteratorImpl::DOMNodeIteratorImpl (DOMDocument* doc,
00039                                     DOMNode* root,
00040                                     DOMNodeFilter::ShowType whatToShow,
00041                                     DOMNodeFilter* nodeFilter,
00042                                     bool expandEntityRef)
00043 :   fRoot(root),
00044     fDocument(doc),
00045     fWhatToShow(whatToShow),
00046     fNodeFilter(nodeFilter),
00047     fExpandEntityReferences(expandEntityRef),
00048     fDetached(false),
00049     fCurrentNode(0),
00050     fForward(true)
00051 {
00052 
00053 }
00054 
00055 
00056 DOMNodeIteratorImpl::DOMNodeIteratorImpl ( const DOMNodeIteratorImpl& toCopy)
00057     : DOMNodeIterator(toCopy),
00058     fRoot(toCopy.fRoot),
00059     fDocument(toCopy.fDocument),
00060     fWhatToShow(toCopy.fWhatToShow),
00061     fNodeFilter(toCopy.fNodeFilter),
00062     fExpandEntityReferences(toCopy.fExpandEntityReferences),
00063     fDetached(toCopy.fDetached),
00064     fCurrentNode(toCopy.fCurrentNode),
00065     fForward(toCopy.fForward)
00066 {
00067 }
00068 
00069 
00070 DOMNodeIteratorImpl& DOMNodeIteratorImpl::operator= (const DOMNodeIteratorImpl& other) {
00071     fRoot                   = other.fRoot;
00072     fCurrentNode            = other.fRoot;
00073     fWhatToShow             = other.fWhatToShow;
00074     fNodeFilter             = other.fNodeFilter;
00075     fForward                = other.fForward;
00076     fDetached               = other.fDetached;
00077     fExpandEntityReferences = other.fExpandEntityReferences;
00078     fDocument               = other.fDocument;
00079     return *this;
00080 }
00081 
00082 DOMNodeIteratorImpl::~DOMNodeIteratorImpl ()
00083 {
00084         fDetached = false;
00085 }
00086 
00087 
00088 void DOMNodeIteratorImpl::detach ()
00089 {
00090         fDetached = true;
00091    ((DOMDocumentImpl *)fDocument)->removeNodeIterator(this);
00092 }
00093 
00094 
00095 DOMNode* DOMNodeIteratorImpl::getRoot() {
00096     return fRoot;
00097 }
00098 
00099 
00100 // Implementation Note: Note that the iterator looks at whatToShow
00101 // and filter values at each call, and therefore one _could_ add
00102 // setters for these values and alter them while iterating!
00103 
00106 DOMNodeFilter::ShowType DOMNodeIteratorImpl::getWhatToShow () {
00107     return fWhatToShow;
00108 }
00109 
00110 
00113 DOMNodeFilter* DOMNodeIteratorImpl::getFilter () {
00114     return fNodeFilter;
00115 }
00116 
00118 bool DOMNodeIteratorImpl::getExpandEntityReferences()
00119 {
00120     return fExpandEntityReferences;
00121 }
00122 
00128 DOMNode* DOMNodeIteratorImpl::nextNode () {
00129         if (fDetached)
00130                 throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager);
00131 
00132     // if root is 0 there is no next node->
00133     if (!fRoot)
00134                         return 0;
00135 
00136     DOMNode* aNextNode = fCurrentNode;
00137     bool accepted = false; // the next node has not been accepted.
00138 
00139     while (!accepted) {
00140 
00141         // if last direction is not forward, repeat node->
00142         if (!fForward && (aNextNode != 0)) {
00143             //System.out.println("nextNode():!fForward:"+fCurrentNode.getNodeName());
00144             aNextNode = fCurrentNode;
00145         } else {
00146         // else get the next node via depth-first
00147             aNextNode = nextNode(aNextNode, true);
00148         }
00149 
00150         fForward = true; //REVIST: should direction be set forward before 0 check?
00151 
00152         // nothing in the list. return 0.
00153         if (!aNextNode) return 0;
00154 
00155         // does node pass the filters and whatToShow?
00156         accepted = acceptNode(aNextNode);
00157         if (accepted) {
00158             // if so, then the node is the current node->
00159             fCurrentNode = aNextNode;
00160             return fCurrentNode;
00161         }
00162     }
00163 
00164     // no nodes, or no accepted nodes.
00165     return 0;
00166 }
00167 
00168 
00173 DOMNode* DOMNodeIteratorImpl::previousNode () {
00174         if (fDetached)
00175                 throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager);
00176 
00177     // if the root is 0, or the current node is 0, return 0.
00178     if (!fRoot || !fCurrentNode) return 0;
00179 
00180     DOMNode* aPreviousNode = fCurrentNode;
00181     bool accepted = false;
00182 
00183     while (!accepted) {
00184 
00185         if (fForward && (aPreviousNode != 0)) {
00186             //repeat last node->
00187             aPreviousNode = fCurrentNode;
00188         } else {
00189             // get previous node in backwards depth first order.
00190             aPreviousNode = previousNode(aPreviousNode);
00191         }
00192 
00193         // we are going backwards
00194         fForward = false;
00195 
00196         // if the new previous node is 0, we're at head or past the root,
00197         // so return 0.
00198         if (!aPreviousNode) return 0;
00199 
00200         // check if node passes filters and whatToShow.
00201         accepted = acceptNode(aPreviousNode);
00202         if (accepted) {
00203             // if accepted, update the current node, and return it.
00204             fCurrentNode = aPreviousNode;
00205             return fCurrentNode;
00206         }
00207     }
00208     // there are no nodes?
00209     return 0;
00210 }
00211 
00212 
00214 bool DOMNodeIteratorImpl::acceptNode (DOMNode* node) {
00215         if (fDetached)
00216                 throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager);
00217 
00218     if (fNodeFilter == 0) {
00219         return ((fWhatToShow & (1 << (node->getNodeType() - 1))) != 0);
00220     } else {
00221         return ((fWhatToShow & (1 << (node->getNodeType() - 1))) != 0)
00222             && fNodeFilter->acceptNode(node) == DOMNodeFilter::FILTER_ACCEPT;
00223     }
00224 }
00225 
00226 
00228 DOMNode* DOMNodeIteratorImpl::matchNodeOrParent (DOMNode* node) {
00229 
00230     for (DOMNode* n = fCurrentNode; n != fRoot; n = n->getParentNode()) {
00231         if (node == n) return n;
00232     }
00233 
00234     return 0;
00235 }
00236 
00237 
00245 DOMNode* DOMNodeIteratorImpl::nextNode (DOMNode* node, bool visitChildren) {
00246         if (fDetached)
00247                 throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager);
00248 
00249     if (!node) return fRoot;
00250 
00251     DOMNode* result = 0;
00252     // only check children if we visit children.
00253     if (visitChildren) {
00254         //if hasChildren, return 1st child.
00255         if ((fExpandEntityReferences || node->getNodeType()!=DOMNode::ENTITY_REFERENCE_NODE) &&
00256             node->hasChildNodes()) {
00257             result = node->getFirstChild();
00258             return result;
00259         }
00260     }
00261 
00262     // if hasSibling, return sibling
00263     if (node != fRoot) {
00264         result = node->getNextSibling();
00265         if (result != 0) return result;
00266 
00267 
00268         // return parent's 1st sibling.
00269         DOMNode* parent = node->getParentNode();
00270         while ((parent != 0) && parent != fRoot) {
00271             result = parent->getNextSibling();
00272             if (result != 0) {
00273                 return result;
00274             } else {
00275                 parent = parent->getParentNode();
00276             }
00277 
00278         } // while (parent != 0 && parent != fRoot) {
00279     }
00280     // end of list, return 0
00281     return 0;
00282 }
00283 
00284 
00289 DOMNode* DOMNodeIteratorImpl::previousNode (DOMNode* node) {
00290         if (fDetached)
00291                 throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager);
00292 
00293     DOMNode* result = 0;
00294 
00295     // if we're at the root, return 0.
00296     if (node == fRoot)
00297                         return 0;
00298 
00299     // get sibling
00300     result = node->getPreviousSibling();
00301     if (!result) {
00302         //if 1st sibling, return parent
00303         result = node->getParentNode();
00304         return result;
00305     }
00306 
00307     // if sibling has children, keep getting last child of child.
00308     if (result->hasChildNodes()) {
00309         while ((fExpandEntityReferences || result->getNodeType()!=DOMNode::ENTITY_REFERENCE_NODE) &&
00310                result->hasChildNodes()) {
00311             result = result->getLastChild();
00312         }
00313     }
00314 
00315     return result;
00316 }
00317 
00318 
00323 void DOMNodeIteratorImpl::removeNode (DOMNode* node) {
00324         if (fDetached)
00325                 throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager);
00326 
00327     // Implementation note: Fix-up means setting the current node properly
00328     // after a remove.
00329 
00330     if (!node) return;
00331 
00332     DOMNode* deleted = matchNodeOrParent(node);
00333 
00334     if (!deleted) return;
00335 
00336     if (fForward) {
00337         fCurrentNode = previousNode(deleted);
00338     } else
00339     // if (!fForward)
00340     {
00341         DOMNode* next = nextNode(deleted, false);
00342         if (next != 0) {
00343             // normal case: there _are_ nodes following this in the iterator.
00344             fCurrentNode = next;
00345         } else {
00346             // the last node in the iterator is to be removed,
00347             // so we set the current node to be the previous one.
00348             fCurrentNode = previousNode(deleted);
00349             fForward = true;
00350         }
00351 
00352     }
00353 
00354 }
00355 
00356 
00357 void DOMNodeIteratorImpl::release()
00358 {
00359     detach();
00360 
00361     // for performance reason, do not recycle pointer
00362     // chance that this is allocated again and again is not usual
00363 }
00364 
00365 XERCES_CPP_NAMESPACE_END