1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.html;
16
17 import org.w3c.dom.Node;
18 import org.w3c.dom.traversal.NodeFilter;
19 import org.w3c.dom.traversal.NodeIterator;
20
21
22
23
24
25
26
27 public class DomNodeIterator implements NodeIterator {
28
29 private final DomNode root_;
30 private final int whatToShow_;
31 private final NodeFilter filter_;
32 private DomNode referenceNode_;
33 private final boolean expandEntityReferences_;
34 private boolean pointerBeforeReferenceNode_;
35
36
37
38
39
40
41
42
43
44
45
46 public DomNodeIterator(final DomNode root, final int whatToShow, final NodeFilter filter,
47 final boolean expandEntityReferences) {
48 root_ = root;
49 referenceNode_ = root;
50 whatToShow_ = whatToShow;
51 filter_ = filter;
52 expandEntityReferences_ = expandEntityReferences;
53 pointerBeforeReferenceNode_ = true;
54 }
55
56
57
58
59 @Override
60 public DomNode getRoot() {
61 return root_;
62 }
63
64
65
66
67 @Override
68 public int getWhatToShow() {
69 return whatToShow_;
70 }
71
72
73
74
75 @Override
76 public boolean getExpandEntityReferences() {
77 return expandEntityReferences_;
78 }
79
80
81
82
83 @Override
84 public NodeFilter getFilter() {
85 return filter_;
86 }
87
88
89
90
91
92 public boolean isPointerBeforeReferenceNode() {
93 return pointerBeforeReferenceNode_;
94 }
95
96
97
98
99 @Override
100 public void detach() {
101
102 }
103
104
105
106
107 @Override
108 public DomNode nextNode() {
109 return traverse(true);
110 }
111
112
113
114
115 @Override
116 public DomNode previousNode() {
117 return traverse(false);
118 }
119
120 private DomNode traverse(final boolean next) {
121 DomNode node = referenceNode_;
122 boolean beforeNode = pointerBeforeReferenceNode_;
123 do {
124 if (next) {
125 if (beforeNode) {
126 beforeNode = false;
127 }
128 else {
129 final DomNode leftChild = getChild(node, true);
130 if (leftChild == null) {
131 final DomNode rightSibling = getSibling(node, false);
132 if (rightSibling == null) {
133 node = getFirstUncleNode(node);
134 }
135 else {
136 node = rightSibling;
137 }
138 }
139 else {
140 node = leftChild;
141 }
142 }
143 }
144 else {
145 if (beforeNode) {
146 DomNode follow = getSibling(node, true);
147 if (follow != null) {
148 while (follow.hasChildNodes()) {
149 final DomNode toFollow = getChild(follow, false);
150 if (toFollow == null) {
151 break;
152 }
153 follow = toFollow;
154 }
155 }
156 node = follow;
157 }
158 else {
159 beforeNode = true;
160 }
161 }
162 }
163 while (node != null && (!isNodeVisible(node) || !isAccepted(node)));
164
165
166
167 referenceNode_ = node;
168 pointerBeforeReferenceNode_ = beforeNode;
169 return node;
170 }
171
172 private boolean isNodeVisible(final Node node) {
173 return (whatToShow_ & HtmlDomTreeWalker.getFlagForNode(node)) != 0;
174 }
175
176 private boolean isAccepted(final Node node) {
177 if (filter_ == null) {
178 return true;
179 }
180 return filter_.acceptNode(node) == NodeFilter.FILTER_ACCEPT;
181 }
182
183
184
185
186
187 private DomNode getFirstUncleNode(final DomNode node) {
188 if (node == null || node == root_) {
189 return null;
190 }
191
192 final DomNode parent = node.getParentNode();
193 if (parent == null || parent == root_) {
194 return null;
195 }
196
197 final DomNode uncle = getSibling(parent, false);
198 if (uncle != null) {
199 return uncle;
200 }
201
202 return getFirstUncleNode(parent);
203 }
204
205 private static DomNode getChild(final DomNode node, final boolean lookLeft) {
206 if (node == null) {
207 return null;
208 }
209
210 final DomNode child;
211 if (lookLeft) {
212 child = node.getFirstChild();
213 }
214 else {
215 child = node.getLastChild();
216 }
217
218 return child;
219 }
220
221 private static DomNode getSibling(final DomNode node, final boolean lookLeft) {
222 if (node == null) {
223 return null;
224 }
225
226 final DomNode sibling;
227 if (lookLeft) {
228 sibling = node.getPreviousSibling();
229 }
230 else {
231 sibling = node.getNextSibling();
232 }
233
234 return sibling;
235 }
236 }