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