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
74 /***
75 * This implementation of 'preceding' works like so:
76 * the preceding axis includes preceding-siblings of this node and their
77 * descendants. Also, for each ancestor node of this node, it includes
78 * all preceding-siblings of that ancestor, and their descendants. Finally, it
79 * includes the ancestor nodes themselves.
80 * <p/>
81 * The reversed descendant-or-self axes that are required are calculated using a
82 * stack of reversed 'child-or-self' axes. When asked for a node, it is always taken
83 * from a child-or-self axis. If it was the last node on that axis, the node is returned.
84 * Otherwise, this axis is pushed on the stack, and the process is repeated with the child-or-self
85 * of the node. Eventually this recurses down to the last descendant of any node, then works
86 * back up to the root.
87 * <p/>
88 * I reckon most object models could provide a faster implementation of the reversed
89 * 'children-or-self' used here.
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 public PrecedingAxisIterator(Object contextNode,
101 Navigator navigator) throws UnsupportedAxisException
102 {
103 this.navigator = navigator;
104 this.ancestorOrSelf = navigator.getAncestorOrSelfAxisIterator(contextNode);
105 this.precedingSibling = JaxenConstants.EMPTY_ITERATOR;
106 this.childrenOrSelf = JaxenConstants.EMPTY_LIST_ITERATOR;
107 this.stack = new ArrayList();
108 }
109
110
111 public boolean hasNext()
112 {
113 try
114 {
115 while (!childrenOrSelf.hasPrevious())
116 {
117 if (stack.isEmpty())
118 {
119 while (!precedingSibling.hasNext())
120 {
121 if (!ancestorOrSelf.hasNext())
122 {
123 return false;
124 }
125 Object contextNode = ancestorOrSelf.next();
126 precedingSibling = new PrecedingSiblingAxisIterator(contextNode, navigator);
127 }
128 Object node = precedingSibling.next();
129 childrenOrSelf = childrenOrSelf(node);
130 }
131 else
132 {
133 childrenOrSelf = (ListIterator) stack.remove(stack.size()-1);
134 }
135 }
136 return true;
137 }
138 catch (UnsupportedAxisException e)
139 {
140 throw new JaxenRuntimeException(e);
141 }
142 }
143
144 private ListIterator childrenOrSelf(Object node)
145 {
146 try
147 {
148 ArrayList reversed = new ArrayList();
149 reversed.add(node);
150 Iterator childAxisIterator = navigator.getChildAxisIterator(node);
151 if (childAxisIterator != null)
152 {
153 while (childAxisIterator.hasNext())
154 {
155 reversed.add(childAxisIterator.next());
156 }
157 }
158 return reversed.listIterator(reversed.size());
159 }
160 catch (UnsupportedAxisException e)
161 {
162 throw new JaxenRuntimeException(e);
163 }
164 }
165
166 public Object next() throws NoSuchElementException
167 {
168 if (!hasNext())
169 {
170 throw new NoSuchElementException();
171 }
172 while (true)
173 {
174 Object result = childrenOrSelf.previous();
175 if (childrenOrSelf.hasPrevious())
176 {
177
178 stack.add(childrenOrSelf);
179 childrenOrSelf = childrenOrSelf(result);
180 continue;
181 }
182 return result;
183 }
184 }
185
186
187 public void remove() throws UnsupportedOperationException
188 {
189 throw new UnsupportedOperationException();
190 }
191 }