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 final DomNode left = getSibling(node, true);
147 if (left == null) {
148 final Node parent = node.getParentNode();
149 if (parent == null) {
150 node = null;
151 }
152 }
153
154 DomNode follow = left;
155 if (follow != null) {
156 while (follow.hasChildNodes()) {
157 final DomNode toFollow = getChild(follow, false);
158 if (toFollow == null) {
159 break;
160 }
161 follow = toFollow;
162 }
163 }
164 node = follow;
165 }
166 else {
167 beforeNode = true;
168 }
169 }
170 }
171 while (node != null && (!isNodeVisible(node) || !isAccepted(node)));
172
173
174
175 referenceNode_ = node;
176 pointerBeforeReferenceNode_ = beforeNode;
177 return node;
178 }
179
180 private boolean isNodeVisible(final Node node) {
181 return (whatToShow_ & HtmlDomTreeWalker.getFlagForNode(node)) != 0;
182 }
183
184 private boolean isAccepted(final Node node) {
185 if (filter_ == null) {
186 return true;
187 }
188 return filter_.acceptNode(node) == NodeFilter.FILTER_ACCEPT;
189 }
190
191
192
193
194
195 private DomNode getFirstUncleNode(final DomNode node) {
196 if (node == null || node == root_) {
197 return null;
198 }
199
200 final DomNode parent = node.getParentNode();
201 if (parent == null || parent == root_) {
202 return null;
203 }
204
205 final DomNode uncle = getSibling(parent, false);
206 if (uncle != null) {
207 return uncle;
208 }
209
210 return getFirstUncleNode(parent);
211 }
212
213 private static DomNode getChild(final DomNode node, final boolean lookLeft) {
214 if (node == null) {
215 return null;
216 }
217
218 final DomNode child;
219 if (lookLeft) {
220 child = node.getFirstChild();
221 }
222 else {
223 child = node.getLastChild();
224 }
225
226 return child;
227 }
228
229 private static DomNode getSibling(final DomNode node, final boolean lookLeft) {
230 if (node == null) {
231 return null;
232 }
233
234 final DomNode sibling;
235 if (lookLeft) {
236 sibling = node.getPreviousSibling();
237 }
238 else {
239 sibling = node.getNextSibling();
240 }
241
242 return sibling;
243 }
244 }