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