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