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 import org.jaxen.JaxenConstants;
52 import org.jaxen.JaxenRuntimeException;
53 import org.jaxen.Navigator;
54 import org.jaxen.UnsupportedAxisException;
55
56 import java.util.ArrayList;
57 import java.util.Iterator;
58 import java.util.ListIterator;
59 import java.util.NoSuchElementException;
60
61 /***
62 * <p>
63 * Represents the XPath <code>preceding</code> axis.
64 * The "<code>preceding</code> axis contains all nodes in the same document as the context
65 * node that are before the context node in document order, excluding any ancestors
66 * and excluding attribute nodes and namespace nodes."
67 *
68 * <p>
69 * This implementation of '<code>preceding</code>' works like so:
70 * the <code>preceding</code> axis includes preceding siblings of this node and
71 * their descendants. Also, for each ancestor node of this node, it includes
72 * all preceding siblings of that ancestor, and their descendants. Finally, it
73 * includes the ancestor nodes themselves.
74 * </p>
75 *
76 * <p>
77 * The reversed <code>descendant-or-self</code> axes that are required are calculated using a
78 * stack of reversed 'child-or-self' axes. When asked for a node, it is always taken
79 * from a child-or-self axis. If it was the last node on that axis, the node is returned.
80 * Otherwise, this axis is pushed on the stack, and the process is repeated with the child-or-self
81 * of the node. Eventually this recurses down to the last descendant of any node, then works
82 * back up to the root.
83 * </p>
84 *
85 * <p>
86 * Most object models could provide a faster implementation of the reversed
87 * 'children-or-self' used here.</p>
88 *
89 * @version 1.2b12
90 */
91 public class PrecedingAxisIterator implements Iterator
92 {
93 private Iterator ancestorOrSelf;
94 private Iterator precedingSibling;
95 private ListIterator childrenOrSelf;
96 private ArrayList stack;
97
98 private Navigator navigator;
99
100 /***
101 * Create a new <code>preceding</code> axis iterator.
102 *
103 * @param contextNode the node to start from
104 * @param navigator the object model specific navigator
105 */
106 public PrecedingAxisIterator(Object contextNode,
107 Navigator navigator) throws UnsupportedAxisException
108 {
109 this.navigator = navigator;
110 this.ancestorOrSelf = navigator.getAncestorOrSelfAxisIterator(contextNode);
111 this.precedingSibling = JaxenConstants.EMPTY_ITERATOR;
112 this.childrenOrSelf = JaxenConstants.EMPTY_LIST_ITERATOR;
113 this.stack = new ArrayList();
114 }
115
116
117 /***
118 * Returns true if there are any preceding nodes remaining; false otherwise.
119 *
120 * @return true if any preceding nodes remain; false otherwise
121 *
122 * @see java.util.Iterator#hasNext()
123 */
124 public boolean hasNext()
125 {
126 try
127 {
128 while (!childrenOrSelf.hasPrevious())
129 {
130 if (stack.isEmpty())
131 {
132 while (!precedingSibling.hasNext())
133 {
134 if (!ancestorOrSelf.hasNext())
135 {
136 return false;
137 }
138 Object contextNode = ancestorOrSelf.next();
139 precedingSibling = new PrecedingSiblingAxisIterator(contextNode, navigator);
140 }
141 Object node = precedingSibling.next();
142 childrenOrSelf = childrenOrSelf(node);
143 }
144 else
145 {
146 childrenOrSelf = (ListIterator) stack.remove(stack.size()-1);
147 }
148 }
149 return true;
150 }
151 catch (UnsupportedAxisException e)
152 {
153 throw new JaxenRuntimeException(e);
154 }
155 }
156
157 private ListIterator childrenOrSelf(Object node)
158 {
159 try
160 {
161 ArrayList reversed = new ArrayList();
162 reversed.add(node);
163 Iterator childAxisIterator = navigator.getChildAxisIterator(node);
164 if (childAxisIterator != null)
165 {
166 while (childAxisIterator.hasNext())
167 {
168 reversed.add(childAxisIterator.next());
169 }
170 }
171 return reversed.listIterator(reversed.size());
172 }
173 catch (UnsupportedAxisException e)
174 {
175 throw new JaxenRuntimeException(e);
176 }
177 }
178
179 /***
180 * Returns the next preceding node.
181 *
182 * @return the next preceding node
183 *
184 * @throws NoSuchElementException if no preceding nodes remain
185 *
186 * @see java.util.Iterator#next()
187 */
188 public Object next() throws NoSuchElementException
189 {
190 if (!hasNext())
191 {
192 throw new NoSuchElementException();
193 }
194 while (true)
195 {
196 Object result = childrenOrSelf.previous();
197 if (childrenOrSelf.hasPrevious())
198 {
199
200 stack.add(childrenOrSelf);
201 childrenOrSelf = childrenOrSelf(result);
202 continue;
203 }
204 return result;
205 }
206 }
207
208
209 /***
210 * This operation is not supported.
211 *
212 * @throws UnsupportedOperationException always
213 */
214 public void remove() throws UnsupportedOperationException
215 {
216 throw new UnsupportedOperationException();
217 }
218
219 }