1//
2// TreeWalker.cpp
3//
4// Library: XML
5// Package: DOM
6// Module: TreeWalker
7//
8// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/DOM/TreeWalker.h"
16#include "Poco/DOM/Node.h"
17#include "Poco/DOM/NodeFilter.h"
18
19
20namespace Poco {
21namespace XML {
22
23
24TreeWalker::TreeWalker(Node* root, unsigned long whatToShow, NodeFilter* pFilter):
25 _pRoot(root),
26 _whatToShow(whatToShow),
27 _pFilter(pFilter),
28 _pCurrent(root)
29{
30}
31
32
33TreeWalker::TreeWalker(const TreeWalker& walker):
34 _pRoot(walker._pRoot),
35 _whatToShow(walker._whatToShow),
36 _pFilter(walker._pFilter),
37 _pCurrent(walker._pCurrent)
38{
39}
40
41
42TreeWalker& TreeWalker::operator = (const TreeWalker& walker)
43{
44 if (&walker != this)
45 {
46 _pRoot = walker._pRoot;
47 _whatToShow = walker._whatToShow;
48 _pFilter = walker._pFilter;
49 _pCurrent = walker._pCurrent;
50 }
51 return *this;
52}
53
54
55TreeWalker::~TreeWalker()
56{
57}
58
59
60void TreeWalker::setCurrentNode(Node* pNode)
61{
62 _pCurrent = pNode;
63}
64
65
66Node* TreeWalker::parentNode()
67{
68 if (!_pCurrent || _pCurrent == _pRoot) return 0;
69
70 Node* pParent = _pCurrent->parentNode();
71 while (pParent && pParent != _pRoot && accept(pParent) != NodeFilter::FILTER_ACCEPT)
72 pParent = pParent->parentNode();
73 if (pParent && accept(pParent) == NodeFilter::FILTER_ACCEPT)
74 _pCurrent = pParent;
75 else
76 pParent = 0;
77 return pParent;
78}
79
80
81Node* TreeWalker::firstChild()
82{
83 if (!_pCurrent) return 0;
84
85 Node* pNode = accept(_pCurrent) != NodeFilter::FILTER_REJECT ? _pCurrent->firstChild() : 0;
86 while (pNode && accept(pNode) != NodeFilter::FILTER_ACCEPT)
87 pNode = pNode->nextSibling();
88 if (pNode)
89 _pCurrent = pNode;
90 return pNode;
91}
92
93
94Node* TreeWalker::lastChild()
95{
96 if (!_pCurrent) return 0;
97
98 Node* pNode = accept(_pCurrent) != NodeFilter::FILTER_REJECT ? _pCurrent->lastChild() : 0;
99 while (pNode && accept(pNode) != NodeFilter::FILTER_ACCEPT)
100 pNode = pNode->previousSibling();
101 if (pNode)
102 _pCurrent = pNode;
103 return pNode;
104}
105
106
107Node* TreeWalker::previousSibling()
108{
109 if (!_pCurrent) return 0;
110
111 Node* pNode = _pCurrent->previousSibling();
112 while (pNode && accept(pNode) != NodeFilter::FILTER_ACCEPT)
113 pNode = pNode->previousSibling();
114 if (pNode)
115 _pCurrent = pNode;
116 return pNode;
117}
118
119
120Node* TreeWalker::nextSibling()
121{
122 if (!_pCurrent) return 0;
123
124 Node* pNode = _pCurrent->nextSibling();
125 while (pNode && accept(pNode) != NodeFilter::FILTER_ACCEPT)
126 pNode = pNode->nextSibling();
127 if (pNode)
128 _pCurrent = pNode;
129 return pNode;
130}
131
132
133Node* TreeWalker::previousNode()
134{
135 if (!_pCurrent) return 0;
136
137 Node* pPrev = previous(_pCurrent);
138 while (pPrev && accept(pPrev) != NodeFilter::FILTER_ACCEPT)
139 pPrev = previous(pPrev);
140 if (pPrev)
141 _pCurrent = pPrev;
142 return pPrev;
143}
144
145
146Node* TreeWalker::nextNode()
147{
148 if (!_pCurrent) return 0;
149
150 Node* pNext = next(_pCurrent);
151 while (pNext && accept(pNext) != NodeFilter::FILTER_ACCEPT)
152 pNext = next(pNext);
153 if (pNext)
154 _pCurrent = pNext;
155 return pNext;
156}
157
158
159int TreeWalker::accept(Node* pNode) const
160{
161 bool accept = false;
162 switch (pNode->nodeType())
163 {
164 case Node::ELEMENT_NODE:
165 accept = (_whatToShow & NodeFilter::SHOW_ELEMENT) != 0; break;
166 case Node::ATTRIBUTE_NODE:
167 accept = (_whatToShow & NodeFilter::SHOW_ATTRIBUTE) != 0; break;
168 case Node::TEXT_NODE:
169 accept = (_whatToShow & NodeFilter::SHOW_TEXT) != 0; break;
170 case Node::CDATA_SECTION_NODE:
171 accept = (_whatToShow & NodeFilter::SHOW_CDATA_SECTION) != 0; break;
172 case Node::ENTITY_REFERENCE_NODE:
173 accept = (_whatToShow & NodeFilter::SHOW_ENTITY_REFERENCE) != 0; break;
174 case Node::ENTITY_NODE:
175 accept = (_whatToShow & NodeFilter::SHOW_ENTITY) != 0; break;
176 case Node::PROCESSING_INSTRUCTION_NODE:
177 accept = (_whatToShow & NodeFilter::SHOW_PROCESSING_INSTRUCTION) != 0; break;
178 case Node::COMMENT_NODE:
179 accept = (_whatToShow & NodeFilter::SHOW_COMMENT) != 0; break;
180 case Node::DOCUMENT_NODE:
181 accept = (_whatToShow & NodeFilter::SHOW_DOCUMENT) != 0; break;
182 case Node::DOCUMENT_TYPE_NODE:
183 accept = (_whatToShow & NodeFilter::SHOW_DOCUMENT_TYPE) != 0; break;
184 case Node::DOCUMENT_FRAGMENT_NODE:
185 accept = (_whatToShow & NodeFilter::SHOW_DOCUMENT_FRAGMENT) != 0; break;
186 case Node::NOTATION_NODE:
187 accept = (_whatToShow & NodeFilter::SHOW_NOTATION) != 0; break;
188 }
189 if (accept && _pFilter)
190 return _pFilter->acceptNode(pNode);
191 else
192 return accept ? NodeFilter::FILTER_ACCEPT : NodeFilter::FILTER_REJECT;
193}
194
195
196Node* TreeWalker::next(Node* pNode) const
197{
198 Node* pNext = accept(pNode) != NodeFilter::FILTER_REJECT ? pNode->firstChild() : 0;
199 if (pNext) return pNext;
200 pNext = pNode;
201 while (pNext && pNext != _pRoot)
202 {
203 Node* pSibling = pNext->nextSibling();
204 if (pSibling) return pSibling;
205 pNext = pNext->parentNode();
206 }
207 return 0;
208}
209
210
211Node* TreeWalker::previous(Node* pNode) const
212{
213 if (pNode == _pRoot) return 0;
214 Node* pPrev = pNode->previousSibling();
215 while (pPrev)
216 {
217 Node* pLastChild = accept(pPrev) != NodeFilter::FILTER_REJECT ? pPrev->lastChild() : 0;
218 if (pLastChild)
219 pPrev = pLastChild;
220 else
221 return pPrev;
222 }
223 return pNode->parentNode();
224}
225
226
227} } // namespace Poco::XML
228