source: icXML/icXML-devel/src/xercesc/dom/impl/DOMDeepNodeListImpl.cpp @ 2777

Last change on this file since 2777 was 2777, checked in by cameron, 7 years ago

Set up to use xercesc/icxercesc root-relative paths for all includes

File size: 6.8 KB
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/*
19 * $Id: DOMDeepNodeListImpl.cpp 678381 2008-07-21 10:15:01Z borisk $
20 */
21
22#include <xercesc/dom/impl/DOMDeepNodeListImpl.hpp>
23#include <xercesc/dom/impl/DOMElementImpl.hpp>
24#include <xercesc/dom/impl/DOMDocumentImpl.hpp>
25#include <xercesc/dom/impl/DOMCasts.hpp>
26#include <icxercesc/dom/impl/DOMNodeImpl.hpp>
27#include <xercesc/util/XMLUniDefs.hpp>
28#include <limits.h>
29
30XERCES_CPP_NAMESPACE_BEGIN
31
32
33static const XMLCh kAstr[] = {chAsterisk, chNull};
34
35DOMDeepNodeListImpl::DOMDeepNodeListImpl(const DOMNode *rootNode,
36                                       const XMLCh *tagName)
37    : fRootNode(rootNode)
38    , fChanges(0)
39    , fCurrentNode(0)
40    , fCurrentIndexPlus1(0)
41    , fNamespaceURI(0)
42    , fMatchAllURI(false)
43    , fMatchURIandTagname(false)
44{
45    fTagName = ((DOMDocumentImpl *)(castToNodeImpl(rootNode)->getOwnerDocument()))->getPooledString(tagName);
46    fMatchAll = XMLString::equals(fTagName, kAstr);
47}
48
49
50//DOM Level 2
51DOMDeepNodeListImpl::DOMDeepNodeListImpl(const DOMNode *rootNode,
52                                       const XMLCh *namespaceURI,
53                                       const XMLCh *localName)
54    : fRootNode(rootNode)
55    , fChanges(0)
56    , fCurrentNode(0)
57    , fCurrentIndexPlus1(0)
58    , fMatchAllURI(false)
59    , fMatchURIandTagname(true)
60{
61    DOMDocumentImpl* doc = (DOMDocumentImpl *)castToNodeImpl(rootNode)->getOwnerDocument();
62
63    fTagName = doc->getPooledString(localName);
64    fMatchAll = XMLString::equals(fTagName, kAstr);
65    fMatchAllURI = XMLString::equals(namespaceURI, kAstr);
66    fNamespaceURI = doc->getPooledString(namespaceURI);
67}
68
69
70DOMDeepNodeListImpl::~DOMDeepNodeListImpl()
71{
72}
73
74XMLSize_t DOMDeepNodeListImpl::getLength() const
75{
76    // Reset cache to beginning of list
77    item(0);
78
79    // Preload all matching elements. (Stops when we run out of subtree!)
80    item(INT_MAX);
81    return fCurrentIndexPlus1;
82}
83
84
85DOMNode *DOMDeepNodeListImpl::item(XMLSize_t index) const
86{
87    return ((DOMDeepNodeListImpl*)this)->cacheItem(index);
88}
89
90// Start from the first child and count forward, 0-based. index>length-1
91// should return 0.
92//
93// Attempts to do only work actually requested, cache work already
94// done, and to flush that cache when the tree has changed.
95//
96// LIMITATION: ????? Unable to tell relevant tree-changes from
97// irrelevant ones.  Doing so in a really useful manner would seem
98// to involve a tree-walk in its own right, or maintaining our data
99// in a parallel tree.
100DOMNode *DOMDeepNodeListImpl::cacheItem(XMLSize_t index)
101{
102    XMLSize_t currentIndexPlus1 = fCurrentIndexPlus1;
103    DOMNode *currentNode = fCurrentNode;
104
105    if (castToParentImpl(fRootNode)->changes() != fChanges)
106    {
107        // Tree changed. Do it all from scratch!
108        currentIndexPlus1 = 0;
109        currentNode = (DOMNode *)fRootNode;
110        fChanges = castToParentImpl(fRootNode)->changes();
111    }
112    else if (currentIndexPlus1 > index+1)
113    {
114        // Interested in something before cached node.  Do it all from scratch!
115        currentIndexPlus1 = 0;
116        currentNode = (DOMNode *)fRootNode;
117    }
118    else if (index+1 == currentIndexPlus1)
119    {
120        // What luck!  User is interested in cached node.
121        return currentNode;
122    }
123
124    DOMNode *nextNode = 0;
125
126// revisit - ???? How efficient is this loop? ????
127
128    // Start at the place in the tree at which we're
129    // currently pointing and count off nodes until we
130    // reach the node of interest or the end of the tree.
131    while (currentIndexPlus1 < index+1 && currentNode != 0)
132    {
133        nextNode = nextMatchingElementAfter(currentNode);
134        if (nextNode == 0)
135            break;
136        currentNode = nextNode;
137        currentIndexPlus1++;
138    }
139
140    fCurrentNode = currentNode;
141    fCurrentIndexPlus1 = currentIndexPlus1;
142
143    // If we found a node at the requested index, make that the current node
144    if (nextNode != 0)
145    {
146        return currentNode;
147    }
148
149    // If we didn't find a node at the requested index, return 0
150    return 0;
151}
152
153
154
155/* Iterative tree-walker. When you have a Parent link, there's often no
156need to resort to recursion. NOTE THAT only Element nodes are matched
157since we're specifically supporting getElementsByTagName().
158*/
159DOMNode *DOMDeepNodeListImpl::nextMatchingElementAfter(DOMNode *current)
160{
161    DOMNode *next;
162    while (current != 0)
163    {
164        // Look down to first child.
165        if (current->hasChildNodes())
166        {
167            current = current->getFirstChild();
168        }
169        // Look right to sibling (but not from root!)
170        else
171        {
172            if (current != fRootNode && 0 != (next = current->getNextSibling()))
173            {
174                current = next;
175            }
176            // Look up and right (but not past root!)
177            else
178            {
179                next = 0;
180                for (;
181                     current != fRootNode; // Stop on return to starting point
182                     current = current->getParentNode())
183                {
184                    next = current->getNextSibling();
185                    if (next != 0)
186                        break;
187                }
188                current = next;
189            }
190        }
191
192        // Have we found an Element with the right tagName?
193        // ("*" matches anything.)
194        if (current != 0 && current != fRootNode &&
195            current->getNodeType() == DOMNode::ELEMENT_NODE) {
196            DOMElement *currElement = (DOMElement *)current;
197
198            if (!fMatchURIandTagname) {        //DOM Level 1
199                if (fMatchAll ||
200                    XMLString::equals(currElement->getTagName(), fTagName))
201                    return current;
202            } else {        //DOM Level 2
203                if (!fMatchAllURI &&
204                    !XMLString::equals(current->getNamespaceURI(), fNamespaceURI))
205                    continue;
206
207                if (fMatchAll ||
208                    XMLString::equals(current->getLocalName(), fTagName))
209                    return current;
210            }
211        }
212
213        // Otherwise continue walking the tree
214    }
215    // Fell out of tree-walk; no more instances found
216    return 0;
217}
218
219XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.