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: DOMTreeWalkerImpl.cpp 671894 2008-06-26 13:29:21Z borisk $
20  */
21 
22 #include "DOMTreeWalkerImpl.hpp"
23 #include "DOMDocumentImpl.hpp"
24 
25 #include <xercesc/dom/DOMDocument.hpp>
26 #include <xercesc/dom/DOMException.hpp>
27 
28 XERCES_CPP_NAMESPACE_BEGIN
29 
30 /** constructor */
DOMTreeWalkerImpl(DOMNode * root,DOMNodeFilter::ShowType whatToShow,DOMNodeFilter * nodeFilter,bool expandEntityRef)31 DOMTreeWalkerImpl::DOMTreeWalkerImpl (
32                                 DOMNode* root,
33                                 DOMNodeFilter::ShowType whatToShow,
34                                 DOMNodeFilter* nodeFilter,
35                                 bool expandEntityRef)
36 :   fWhatToShow(whatToShow),
37     fNodeFilter(nodeFilter),
38     fCurrentNode(root),
39     fRoot(root),
40     fExpandEntityReferences(expandEntityRef)
41 {
42 }
43 
44 
DOMTreeWalkerImpl(const DOMTreeWalkerImpl & twi)45 DOMTreeWalkerImpl::DOMTreeWalkerImpl (const DOMTreeWalkerImpl& twi)
46 :   DOMTreeWalker(twi),
47     fWhatToShow(twi.fWhatToShow),
48     fNodeFilter(twi.fNodeFilter),
49     fCurrentNode(twi.fCurrentNode),
50     fRoot(twi.fRoot),
51     fExpandEntityReferences(twi.fExpandEntityReferences)
52 {
53 }
54 
55 
operator =(const DOMTreeWalkerImpl & twi)56 DOMTreeWalkerImpl& DOMTreeWalkerImpl::operator= (const DOMTreeWalkerImpl& twi) {
57     if (this != &twi)
58     {
59         fCurrentNode            = twi.fCurrentNode;
60         fRoot                   = twi.fRoot;
61         fWhatToShow             = twi.fWhatToShow;
62         fNodeFilter             = twi.fNodeFilter;
63 		fExpandEntityReferences = twi.fExpandEntityReferences;
64     }
65 
66     return *this;
67 }
68 
69 
70 
71 /** Return the root node */
getRoot()72 DOMNode* DOMTreeWalkerImpl::getRoot () {
73     return fRoot;
74 }
75 
76 
77 /** Return the whatToShow value */
getWhatToShow()78 DOMNodeFilter::ShowType DOMTreeWalkerImpl::getWhatToShow () {
79     return fWhatToShow;
80 }
81 
82 
83 /** Return the NodeFilter */
getFilter()84 DOMNodeFilter* DOMTreeWalkerImpl::getFilter () {
85     return fNodeFilter;
86 }
87 
88 /** Get the expandEntity reference flag. */
getExpandEntityReferences()89 bool DOMTreeWalkerImpl::getExpandEntityReferences() {
90     return fExpandEntityReferences;
91 }
92 
93 
94 
95 /** Return the current Node. */
getCurrentNode()96 DOMNode* DOMTreeWalkerImpl::getCurrentNode () {
97 
98     return fCurrentNode;
99 }
100 
101 
102 /** Return the current Node. */
setCurrentNode(DOMNode * node)103 void DOMTreeWalkerImpl::setCurrentNode (DOMNode* node) {
104 
105     if (!node)
106         throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, GetDOMTreeWalkerMemoryManager);
107 
108     fCurrentNode = node;
109 }
110 
111 
112 /** Return the parent Node from the current node,
113  *  after applying filter, whatToshow.
114  *  If result is not null, set the current Node.
115  */
parentNode()116 DOMNode* DOMTreeWalkerImpl::parentNode () {
117 
118     if (!fCurrentNode) return 0;
119 
120     DOMNode* node = getParentNode(fCurrentNode);
121     if (node != 0) {
122         fCurrentNode = node;
123     }
124     return node;
125 
126 }
127 
128 
129 /** Return the first child Node from the current node,
130  *  after applying filter, whatToshow.
131  *  If result is not null, set the current Node.
132  */
firstChild()133 DOMNode* DOMTreeWalkerImpl::firstChild () {
134 
135     if (!fCurrentNode) return 0;
136 
137     if(!fExpandEntityReferences && fCurrentNode->getNodeType()==DOMNode::ENTITY_REFERENCE_NODE)
138         return 0;
139 
140     DOMNode* node = getFirstChild(fCurrentNode);
141 
142     if (node != 0) {
143         fCurrentNode = node;
144     }
145     return node;
146 }
147 
148 
149 /** Return the last child Node from the current node,
150  *  after applying filter, whatToshow.
151  *  If result is not null, set the current Node.
152  */
lastChild()153 DOMNode* DOMTreeWalkerImpl::lastChild () {
154 
155     if (!fCurrentNode) return 0;
156 
157     if(!fExpandEntityReferences && fCurrentNode->getNodeType()==DOMNode::ENTITY_REFERENCE_NODE)
158         return 0;
159 
160     DOMNode* node = getLastChild(fCurrentNode);
161     if (node != 0) {
162         fCurrentNode = node;
163     }
164     return node;
165 }
166 
167 
168 /** Return the previous sibling Node from the current node,
169  *  after applying filter, whatToshow.
170  *  If result is not null, set the current Node.
171  */
172 
previousSibling()173 DOMNode* DOMTreeWalkerImpl::previousSibling () {
174 
175     if (!fCurrentNode) return 0;
176 
177     DOMNode* node = getPreviousSibling(fCurrentNode);
178     if (node != 0) {
179         fCurrentNode = node;
180     }
181     return node;
182 }
183 
184 
185 /** Return the next sibling Node from the current node,
186  *  after applying filter, whatToshow.
187  *  If result is not null, set the current Node.
188  */
189 
nextSibling()190 DOMNode* DOMTreeWalkerImpl::nextSibling () {
191 
192     if (!fCurrentNode) return 0;
193 
194     DOMNode* node = getNextSibling(fCurrentNode);
195     if (node != 0) {
196         fCurrentNode = node;
197     }
198     return node;
199 }
200 
201 
202 /** Return the previous Node from the current node,
203  *  after applying filter, whatToshow.
204  *  If result is not null, set the current Node.
205  */
206 
previousNode()207 DOMNode* DOMTreeWalkerImpl::previousNode () {
208 
209     if (!fCurrentNode) return 0;
210 
211     // get sibling
212     DOMNode* node = getPreviousSibling(fCurrentNode);
213     if (node == 0) {
214         node = getParentNode(fCurrentNode);
215         if ( node != 0) {
216             fCurrentNode = node;
217         }
218         return node;
219     }
220     else {
221 
222         // get the lastChild of result.
223         DOMNode* lastChild  = getLastChild(node);
224 
225         // if there is a lastChild which passes filters return it.
226         if (lastChild != 0) {
227             fCurrentNode = lastChild;
228         }
229         else {
230             fCurrentNode = node;
231         }
232         return fCurrentNode;
233     }
234 }
235 
236 
237 /** Return the next Node from the current node,
238  *  after applying filter, whatToshow.
239  *  If result is not null, set the current Node.
240  */
241 
nextNode()242 DOMNode* DOMTreeWalkerImpl::nextNode () {
243 
244     if (!fCurrentNode) return 0;
245 
246     DOMNode* node = getFirstChild(fCurrentNode);
247 
248     if (node != 0) {
249         fCurrentNode = node;
250         return node;
251     }
252     else {
253 
254         node = getNextSibling(fCurrentNode);
255 
256         if (node != 0) {
257             fCurrentNode = node;
258             return node;
259         }
260         else {
261 
262             // return parent's 1st sibling.
263             DOMNode* parent = getParentNode(fCurrentNode);
264             while ( parent != 0) {
265                 node = getNextSibling(parent);
266                 if (node != 0) {
267                     fCurrentNode = node;
268                     return node;
269                 } else {
270                     parent = getParentNode(parent);
271                 }
272             }
273             return node;
274         }
275     }
276 }
277 
278 
279 /** Internal function.
280  *  Return the parent Node, from the input node
281  *  after applying filter, whatToshow.
282  *  The current node is not consulted or set.
283  */
284 
getParentNode(DOMNode * node)285 DOMNode* DOMTreeWalkerImpl::getParentNode (DOMNode* node) {
286 
287     if (!node || node == fRoot) return 0;
288 
289     DOMNode* newNode = node->getParentNode();
290     if (!newNode)  return 0;
291 
292     short accept = acceptNode(newNode);
293 
294     if (accept == DOMNodeFilter::FILTER_ACCEPT)
295         return newNode;
296 
297     return getParentNode(newNode);
298 
299 }
300 
301 
302 /** Internal function.
303  *  Return the nextSibling Node, from the input node
304  *  after applying filter, whatToshow.
305  *  The current node is not consulted or set.
306  */
307 
getNextSibling(DOMNode * node)308 DOMNode* DOMTreeWalkerImpl::getNextSibling (DOMNode* node) {
309 
310     if (!node || node == fRoot) return 0;
311 
312     DOMNode* newNode = node->getNextSibling();
313     if (!newNode) {
314 
315         newNode = node->getParentNode();
316 
317         if (!newNode || node == fRoot)  return 0;
318 
319         short parentAccept = acceptNode(newNode);
320 
321         if (parentAccept == DOMNodeFilter::FILTER_SKIP) {
322             return getNextSibling(newNode);
323         }
324 
325         return 0;
326     }
327 
328     short accept = acceptNode(newNode);
329 
330     if (accept == DOMNodeFilter::FILTER_ACCEPT)
331         return newNode;
332     else
333     if (accept == DOMNodeFilter::FILTER_SKIP) {
334         DOMNode* fChild =  getFirstChild(newNode);
335         if (!fChild && !newNode->hasChildNodes()) {
336             return getNextSibling(newNode);
337         }
338         return fChild;
339     }
340     return getNextSibling(newNode);
341 
342 }
343 
344 
345 /** Internal function.
346  *  Return the previous sibling Node, from the input node
347  *  after applying filter, whatToshow.
348  *  The current node is not consulted or set.
349  */
350 
getPreviousSibling(DOMNode * node)351 DOMNode* DOMTreeWalkerImpl::getPreviousSibling (DOMNode* node) {
352 
353     if (!node || node == fRoot) return 0;
354 
355     DOMNode* newNode = node->getPreviousSibling();
356     if (!newNode) {
357 
358         newNode = node->getParentNode();
359         if (!newNode || node == fRoot)  return 0;
360 
361         short parentAccept = acceptNode(newNode);
362 
363         if (parentAccept == DOMNodeFilter::FILTER_SKIP) {
364             return getPreviousSibling(newNode);
365         }
366 
367         return 0;
368     }
369 
370     short accept = acceptNode(newNode);
371 
372     if (accept == DOMNodeFilter::FILTER_ACCEPT)
373         return newNode;
374     else
375     if (accept == DOMNodeFilter::FILTER_SKIP) {
376         DOMNode* fChild =  getLastChild(newNode);
377         if (!fChild && !newNode->hasChildNodes()) {
378             return getPreviousSibling(newNode);
379         }
380         return fChild;
381     }
382     return getPreviousSibling(newNode);
383 
384 }
385 
386 
387 /** Internal function.
388  *  Return the first child Node, from the input node
389  *  after applying filter, whatToshow.
390  *  The current node is not consulted or set.
391  */
392 
getFirstChild(DOMNode * node)393 DOMNode* DOMTreeWalkerImpl::getFirstChild (DOMNode* node) {
394 
395     if (!node) return 0;
396 
397     if(!fExpandEntityReferences && node->getNodeType()==DOMNode::ENTITY_REFERENCE_NODE)
398         return 0;
399 
400     DOMNode* newNode = node->getFirstChild();
401     if (!newNode)  return 0;
402 
403     short accept = acceptNode(newNode);
404 
405     if (accept == DOMNodeFilter::FILTER_ACCEPT)
406         return newNode;
407     else
408     if (accept == DOMNodeFilter::FILTER_SKIP
409         && newNode->hasChildNodes())
410     {
411         return getFirstChild(newNode);
412     }
413     return getNextSibling(newNode);
414 
415 }
416 
417 
418 /** Internal function.
419  *  Return the last child Node, from the input node
420  *  after applying filter, whatToshow.
421  *  The current node is not consulted or set.
422  */
423 
getLastChild(DOMNode * node)424 DOMNode* DOMTreeWalkerImpl::getLastChild (DOMNode* node) {
425 
426     if (!node) return 0;
427 
428     if(!fExpandEntityReferences && node->getNodeType()==DOMNode::ENTITY_REFERENCE_NODE)
429         return 0;
430 
431     DOMNode* newNode = node->getLastChild();
432     if (!newNode)  return 0;
433 
434     short accept = acceptNode(newNode);
435 
436     if (accept == DOMNodeFilter::FILTER_ACCEPT)
437         return newNode;
438     else
439     if (accept == DOMNodeFilter::FILTER_SKIP
440         && newNode->hasChildNodes())
441     {
442         return getLastChild(newNode);
443     }
444     return getPreviousSibling(newNode);
445 
446 }
447 
448 
449 /** The node is accepted if it passes the whatToShow and the filter. */
450 
acceptNode(DOMNode * node)451 short DOMTreeWalkerImpl::acceptNode (DOMNode* node) {
452 
453     if (fNodeFilter == 0) {
454         if ( ( fWhatToShow & (1 << (node->getNodeType() - 1))) != 0)
455         {
456             return DOMNodeFilter::FILTER_ACCEPT;
457         }
458         else
459         {
460             return DOMNodeFilter::FILTER_SKIP;
461         }
462     } else {
463         // REVISIT: This logic is unclear from the spec!
464         if ((fWhatToShow & (1 << (node->getNodeType() - 1))) != 0 ) {
465             return fNodeFilter->acceptNode(node);
466         } else {
467             // what to show has failed!
468             if (fNodeFilter->acceptNode(node) == DOMNodeFilter::FILTER_REJECT) {
469                 return DOMNodeFilter::FILTER_REJECT;
470             } else {
471                 return DOMNodeFilter::FILTER_SKIP;
472             }
473         }
474     }
475 }
476 
477 
release()478 void DOMTreeWalkerImpl::release()
479 {
480     // for performance reason, do not recycle pointer
481     // chance that this is allocated again and again is not usual
482 }
483 
484 XERCES_CPP_NAMESPACE_END
485