1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.jxpath.ri;
19
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.HashSet;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.NoSuchElementException;
26
27 import org.apache.commons.jxpath.BasicNodeSet;
28 import org.apache.commons.jxpath.ExpressionContext;
29 import org.apache.commons.jxpath.JXPathContext;
30 import org.apache.commons.jxpath.JXPathException;
31 import org.apache.commons.jxpath.NodeSet;
32 import org.apache.commons.jxpath.Pointer;
33 import org.apache.commons.jxpath.ri.axes.RootContext;
34 import org.apache.commons.jxpath.ri.model.NodePointer;
35 import org.apache.commons.jxpath.util.ReverseComparator;
36
37
38
39
40
41
42
43 public abstract class EvalContext implements ExpressionContext, Iterator {
44
45
46 protected EvalContext parentContext;
47
48 protected RootContext rootContext;
49
50 protected int position;
51 private boolean startedSetIteration;
52 private boolean done;
53 private boolean hasPerformedIteratorStep;
54 private Iterator<Pointer> pointerIterator;
55
56
57
58
59
60
61 public EvalContext(final EvalContext parentContext) {
62 this.parentContext = parentContext;
63 }
64
65
66
67
68
69
70 private boolean constructIterator() {
71 final HashSet<Pointer> set = new HashSet<>();
72 final ArrayList<Pointer> list = new ArrayList<>();
73 while (nextSet()) {
74 while (nextNode()) {
75 final NodePointer pointer = getCurrentNodePointer();
76 if (!set.contains(pointer)) {
77 set.add(pointer);
78 list.add(pointer);
79 }
80 }
81 }
82 if (list.isEmpty()) {
83 return false;
84 }
85 sortPointers(list);
86 pointerIterator = list.iterator();
87 return true;
88 }
89
90
91
92
93
94
95 @Override
96 public List<Pointer> getContextNodeList() {
97 final int pos = position;
98 if (pos != 0) {
99 reset();
100 }
101 final List<Pointer> list = new ArrayList<>();
102 while (nextNode()) {
103 list.add(getCurrentNodePointer());
104 }
105 if (pos != 0) {
106 setPosition(pos);
107 } else {
108 reset();
109 }
110 return list;
111 }
112
113 @Override
114 public Pointer getContextNodePointer() {
115 return getCurrentNodePointer();
116 }
117
118
119
120
121
122
123 public abstract NodePointer getCurrentNodePointer();
124
125
126
127
128
129
130 public int getCurrentPosition() {
131 return position;
132 }
133
134
135
136
137
138
139 public int getDocumentOrder() {
140 return parentContext != null && parentContext.isChildOrderingRequired() ? 1 : 0;
141 }
142
143 @Override
144 public JXPathContext getJXPathContext() {
145 return getRootContext().getJXPathContext();
146 }
147
148
149
150
151
152
153
154 public NodeSet getNodeSet() {
155 if (position != 0) {
156 throw new JXPathException("Simultaneous operations: " + "should not request pointer list while " + "iterating over an EvalContext");
157 }
158 final BasicNodeSet set = new BasicNodeSet();
159 while (nextSet()) {
160 while (nextNode()) {
161 set.add((Pointer) getCurrentNodePointer().clone());
162 }
163 }
164 return set;
165 }
166
167 @Override
168 public int getPosition() {
169 return position;
170 }
171
172
173
174
175
176
177 public RootContext getRootContext() {
178 if (rootContext == null) {
179 rootContext = parentContext.getRootContext();
180 }
181 return rootContext;
182 }
183
184
185
186
187
188
189 public Pointer getSingleNodePointer() {
190 reset();
191 while (nextSet()) {
192 if (nextNode()) {
193 return getCurrentNodePointer();
194 }
195 }
196 return null;
197 }
198
199
200
201
202
203
204
205 public Object getValue() {
206 return getNodeSet();
207 }
208
209
210
211
212
213
214 @Override
215 public boolean hasNext() {
216 if (pointerIterator != null) {
217 return pointerIterator.hasNext();
218 }
219 if (getDocumentOrder() != 0) {
220 return constructIterator();
221 }
222 if (!done && !hasPerformedIteratorStep) {
223 performIteratorStep();
224 }
225 return !done;
226 }
227
228
229
230
231
232
233
234 public boolean isChildOrderingRequired() {
235
236
237 return getDocumentOrder() != 0;
238 }
239
240
241
242
243
244
245 @Override
246 public Object next() {
247 if (pointerIterator != null) {
248 return pointerIterator.next();
249 }
250 if (getDocumentOrder() != 0) {
251 if (!constructIterator()) {
252 throw new NoSuchElementException();
253 }
254 return pointerIterator.next();
255 }
256 if (!done && !hasPerformedIteratorStep) {
257 performIteratorStep();
258 }
259 if (done) {
260 throw new NoSuchElementException();
261 }
262 hasPerformedIteratorStep = false;
263 return getCurrentNodePointer();
264 }
265
266
267
268
269
270
271 public abstract boolean nextNode();
272
273
274
275
276
277
278 public boolean nextSet() {
279 reset();
280
281
282
283 if (!startedSetIteration) {
284 startedSetIteration = true;
285 while (parentContext.nextSet()) {
286 if (parentContext.nextNode()) {
287 return true;
288 }
289 }
290 return false;
291 }
292
293
294 if (parentContext.nextNode()) {
295 return true;
296 }
297
298
299 while (parentContext.nextSet()) {
300 if (parentContext.nextNode()) {
301 return true;
302 }
303 }
304 return false;
305 }
306
307
308
309
310 private void performIteratorStep() {
311 done = true;
312 if (position != 0 && nextNode()) {
313 done = false;
314 } else {
315 while (nextSet()) {
316 if (nextNode()) {
317 done = false;
318 break;
319 }
320 }
321 }
322 hasPerformedIteratorStep = true;
323 }
324
325
326
327
328
329
330 @Override
331 public void remove() {
332 throw new UnsupportedOperationException("JXPath iterators cannot remove nodes");
333 }
334
335
336
337
338 public void reset() {
339 position = 0;
340 }
341
342
343
344
345
346
347
348
349 public boolean setPosition(final int position) {
350 this.position = position;
351 return true;
352 }
353
354
355
356
357
358
359 protected void sortPointers(final List l) {
360 switch (getDocumentOrder()) {
361 case 1:
362 Collections.sort(l);
363 break;
364 case -1:
365 Collections.sort(l, ReverseComparator.INSTANCE);
366 break;
367 default:
368 break;
369 }
370 }
371
372 @Override
373 public String toString() {
374 final Pointer ptr = getContextNodePointer();
375 return ptr == null ? "Empty expression context" : "Expression context [" + getPosition() + "] " + ptr.asPath();
376 }
377 }