1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.jxpath.ri.axes;
19
20 import java.util.Stack;
21
22 import org.apache.commons.jxpath.Pointer;
23 import org.apache.commons.jxpath.ri.Compiler;
24 import org.apache.commons.jxpath.ri.EvalContext;
25 import org.apache.commons.jxpath.ri.compiler.NodeTest;
26 import org.apache.commons.jxpath.ri.compiler.NodeTypeTest;
27 import org.apache.commons.jxpath.ri.model.NodeIterator;
28 import org.apache.commons.jxpath.ri.model.NodePointer;
29
30
31
32
33 public class DescendantContext extends EvalContext {
34
35 private static final NodeTest ELEMENT_NODE_TEST = new NodeTypeTest(Compiler.NODE_TYPE_NODE);
36 private final NodeTest nodeTest;
37 private boolean setStarted;
38 private Stack<NodeIterator> stack;
39 private NodePointer currentNodePointer;
40 private final boolean includeSelf;
41
42
43
44
45
46
47
48
49 public DescendantContext(final EvalContext parentContext, final boolean includeSelf, final NodeTest nodeTest) {
50 super(parentContext);
51 this.includeSelf = includeSelf;
52 this.nodeTest = nodeTest;
53 }
54
55 @Override
56 public NodePointer getCurrentNodePointer() {
57 if (position == 0 && !setPosition(1)) {
58 return null;
59 }
60 return currentNodePointer;
61 }
62
63 @Override
64 public boolean isChildOrderingRequired() {
65 return true;
66 }
67
68
69
70
71
72
73 private boolean isRecursive() {
74 final Object node = currentNodePointer.getNode();
75 for (int i = stack.size() - 1; --i >= 0;) {
76 final NodeIterator it = stack.get(i);
77 final Pointer pointer = it.getNodePointer();
78 if (pointer != null && pointer.getNode() == node) {
79 return true;
80 }
81 }
82 return false;
83 }
84
85 @Override
86 public boolean nextNode() {
87 if (!setStarted) {
88 setStarted = true;
89 if (stack == null) {
90 stack = new Stack<>();
91 } else {
92 stack.clear();
93 }
94 currentNodePointer = parentContext.getCurrentNodePointer();
95 if (currentNodePointer != null) {
96 if (!currentNodePointer.isLeaf()) {
97 stack.push(currentNodePointer.childIterator(ELEMENT_NODE_TEST, false, null));
98 }
99 if (includeSelf && currentNodePointer.testNode(nodeTest)) {
100 position++;
101 return true;
102 }
103 }
104 }
105 while (!stack.isEmpty()) {
106 final NodeIterator it = stack.peek();
107 if (it.setPosition(it.getPosition() + 1)) {
108 currentNodePointer = it.getNodePointer();
109 if (!isRecursive()) {
110 if (!currentNodePointer.isLeaf()) {
111 stack.push(currentNodePointer.childIterator(ELEMENT_NODE_TEST, false, null));
112 }
113 if (currentNodePointer.testNode(nodeTest)) {
114 position++;
115 return true;
116 }
117 }
118 } else {
119
120
121 stack.pop();
122 }
123 }
124 return false;
125 }
126
127 @Override
128 public void reset() {
129 super.reset();
130 setStarted = false;
131 }
132
133 @Override
134 public boolean setPosition(final int position) {
135 if (position < this.position) {
136 reset();
137 }
138 while (this.position < position) {
139 if (!nextNode()) {
140 return false;
141 }
142 }
143 return true;
144 }
145 }