1 package org.jaxen.util;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 import org.jaxen.JaxenConstants;
65 import org.jaxen.JaxenRuntimeException;
66 import org.jaxen.Navigator;
67 import org.jaxen.UnsupportedAxisException;
68
69 import java.util.ArrayList;
70 import java.util.Iterator;
71 import java.util.ListIterator;
72 import java.util.NoSuchElementException;
73 import java.util.Stack;
74
75 /***
76 * This implementation of 'preceding' works like so:
77 * the preceding axis includes preceding-siblings of this node and their
78 * descendants. Also, for each ancestor node of this node, it includes
79 * all preceding-siblings of that ancestor, and their descendants. Finally, it
80 * includes the ancestor nodes themselves.
81 * <p/>
82 * The reversed descendant-or-self axes that are required are calculated using a
83 * stack of reversed 'child-or-self' axes. When asked for a node, it is always taken
84 * from a child-or-self axis. If it was the last node on that axis, the node is returned.
85 * Otherwise, this axis is pushed on the stack, and the process is repeated with the child-or-self
86 * of the node. Eventually this recurses down to the last descendant of any node, then works
87 * back up to the root.
88 * <p/>
89 * I reckon most object models could provide a faster implementation of the reversed
90 * 'children-or-self' used here.
91 */
92 public class PrecedingAxisIterator implements Iterator
93 {
94 private Iterator ancestorOrSelf;
95 private Iterator precedingSibling;
96 private ListIterator childrenOrSelf;
97 private Stack stack;
98
99 private Navigator navigator;
100
101 public PrecedingAxisIterator(Object contextNode,
102 Navigator navigator) throws UnsupportedAxisException
103 {
104 this.navigator = navigator;
105 this.ancestorOrSelf = navigator.getAncestorOrSelfAxisIterator(contextNode);
106 this.precedingSibling = JaxenConstants.EMPTY_ITERATOR;
107 this.childrenOrSelf = JaxenConstants.EMPTY_LIST_ITERATOR;
108 this.stack = new Stack();
109 }
110
111
112 public boolean hasNext()
113 {
114 try
115 {
116 while (!childrenOrSelf.hasPrevious())
117 {
118 if (stack.isEmpty())
119 {
120 while (!precedingSibling.hasNext())
121 {
122 if (!ancestorOrSelf.hasNext())
123 {
124 return false;
125 }
126 Object contextNode = ancestorOrSelf.next();
127 precedingSibling = new PrecedingSiblingAxisIterator(contextNode, navigator);
128 }
129 Object node = precedingSibling.next();
130 childrenOrSelf = childrenOrSelf(node);
131 }
132 else
133 {
134 childrenOrSelf = (ListIterator) stack.pop();
135 }
136 }
137 return true;
138 }
139 catch (UnsupportedAxisException e)
140 {
141 throw new JaxenRuntimeException(e);
142 }
143 }
144
145 private ListIterator childrenOrSelf(Object node)
146 {
147 try
148 {
149 ArrayList reversed = new ArrayList();
150 reversed.add(node);
151 Iterator childAxisIterator = navigator.getChildAxisIterator(node);
152 if (childAxisIterator != null)
153 {
154 while (childAxisIterator.hasNext())
155 {
156 reversed.add(childAxisIterator.next());
157 }
158 }
159 return reversed.listIterator(reversed.size());
160 }
161 catch (UnsupportedAxisException e)
162 {
163 throw new JaxenRuntimeException(e);
164 }
165 }
166
167 public Object next() throws NoSuchElementException
168 {
169 if (!hasNext())
170 {
171 throw new NoSuchElementException();
172 }
173 while (true)
174 {
175 Object result = childrenOrSelf.previous();
176 if (childrenOrSelf.hasPrevious())
177 {
178
179 stack.push(childrenOrSelf);
180 childrenOrSelf = childrenOrSelf(result);
181 continue;
182 }
183 return result;
184 }
185 }
186
187
188 public void remove() throws UnsupportedOperationException
189 {
190 throw new UnsupportedOperationException();
191 }
192 }