1
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 package org.jaxen.expr;
52
53 import java.io.Serializable;
54 import java.util.ArrayList;
55 import java.util.Collections;
56 import java.util.Iterator;
57 import java.util.List;
58 import org.jaxen.Context;
59 import org.jaxen.ContextSupport;
60 import org.jaxen.JaxenException;
61 import org.jaxen.function.BooleanFunction;
62
63 /***
64 * <p>
65 * Represents the collection of predicates that follow the node-test in a
66 * location path.
67 * </p>
68 *
69 * <p>
70 * There is no rule that the same predicate may not
71 * appear twice in an XPath expression, nor does this class enforce any such rule.
72 * This is implemented more as a list than a set. However, adding the swme predicate
73 * twice should have no effect on the final result other than slowing it down.
74 * </p>
75 */
76 public class PredicateSet implements Serializable
77 {
78
79 private static final long serialVersionUID = -7166491740228977853L;
80
81 private List predicates;
82
83 /***
84 * Create a new empty predicate set.
85 */
86 public PredicateSet()
87 {
88 this.predicates = Collections.EMPTY_LIST;
89 }
90
91 /***
92 * Add a predicate to the set.
93 *
94 * @param predicate the predicate to be inserted
95 */
96 public void addPredicate(Predicate predicate)
97 {
98 if ( this.predicates == Collections.EMPTY_LIST )
99 {
100 this.predicates = new ArrayList();
101 }
102
103 this.predicates.add( predicate );
104 }
105
106 /***
107 * Returns the list containing the predicates.
108 * This list is live, not a copy.
109 *
110 * @return a live list of predicates
111 */
112 public List getPredicates()
113 {
114 return this.predicates;
115 }
116
117 /***
118 * Simplify each of the predicates in the list.
119 */
120 public void simplify()
121 {
122 Iterator predIter = this.predicates.iterator();
123 Predicate eachPred = null;
124
125 while ( predIter.hasNext() )
126 {
127 eachPred = (Predicate) predIter.next();
128 eachPred.simplify();
129 }
130 }
131
132 /***
133 * Returns the XPath string containing each of the predicates.
134 *
135 * @return the XPath string containing each of the predicates
136 */
137 public String getText()
138 {
139 StringBuffer buf = new StringBuffer();
140
141 Iterator predIter = this.predicates.iterator();
142 Predicate eachPred = null;
143
144 while ( predIter.hasNext() )
145 {
146 eachPred = (Predicate) predIter.next();
147 buf.append( eachPred.getText() );
148 }
149
150 return buf.toString();
151 }
152
153 /***
154 * <p>Returns true if any of the supplied nodes satisfy
155 * all the predicates in the set. Returns false if none of the supplied
156 * nodes matches all the predicates in the set. Returns false if the
157 * node-set is empty.</p>
158 *
159 * @param contextNodeSet the nodes to test against these predicates
160 * @param support ????
161 * @return true if any node in the contextNodeSet matches all the predicates
162 * @throws JaxenException
163 */
164 protected boolean evaluateAsBoolean(List contextNodeSet,
165 ContextSupport support) throws JaxenException
166 {
167 return anyMatchingNode( contextNodeSet, support );
168 }
169
170 private boolean anyMatchingNode(List contextNodeSet, ContextSupport support)
171 throws JaxenException {
172
173 if (predicates.size() == 0) {
174 return false;
175 }
176 Iterator predIter = predicates.iterator();
177
178
179 List nodes2Filter = contextNodeSet;
180
181 while(predIter.hasNext()) {
182 final int nodes2FilterSize = nodes2Filter.size();
183
184 Context predContext = new Context(support);
185 List tempList = new ArrayList(1);
186 predContext.setNodeSet(tempList);
187
188
189 for (int i = 0; i < nodes2FilterSize; ++i) {
190 Object contextNode = nodes2Filter.get(i);
191 tempList.clear();
192 tempList.add(contextNode);
193 predContext.setNodeSet(tempList);
194
195 predContext.setPosition(i + 1);
196 predContext.setSize(nodes2FilterSize);
197 Object predResult = ((Predicate)predIter.next()).evaluate(predContext);
198 if (predResult instanceof Number) {
199
200
201 int proximity = ((Number) predResult).intValue();
202 if (proximity == (i + 1)) {
203 return true;
204 }
205 }
206 else {
207 Boolean includes =
208 BooleanFunction.evaluate(predResult,
209 predContext.getNavigator());
210 if (includes.booleanValue()) {
211 return true;
212 }
213 }
214 }
215 }
216
217 return false;
218 }
219
220
221
222
223 /***
224 * <p>Returns all of the supplied nodes that satisfy
225 * all the predicates in the set. </p>
226 *
227 * @param contextNodeSet the nodes to test against these predicates
228 * @param support ????
229 * @return all the nodes that match each of the predicates
230 * @throws JaxenException
231 */
232 protected List evaluatePredicates(List contextNodeSet, ContextSupport support)
233 throws JaxenException {
234
235 if (predicates.size() == 0) {
236 return contextNodeSet;
237 }
238 Iterator predIter = predicates.iterator();
239
240
241 List nodes2Filter = contextNodeSet;
242
243 while(predIter.hasNext()) {
244 nodes2Filter =
245 applyPredicate((Predicate)predIter.next(), nodes2Filter, support);
246 }
247
248 return nodes2Filter;
249 }
250
251 public List applyPredicate(Predicate predicate, List nodes2Filter, ContextSupport support)
252 throws JaxenException {
253 final int nodes2FilterSize = nodes2Filter.size();
254 List filteredNodes = new ArrayList(nodes2FilterSize);
255
256 Context predContext = new Context(support);
257 List tempList = new ArrayList(1);
258 predContext.setNodeSet(tempList);
259
260
261 for (int i = 0; i < nodes2FilterSize; ++i) {
262 Object contextNode = nodes2Filter.get(i);
263 tempList.clear();
264 tempList.add(contextNode);
265 predContext.setNodeSet(tempList);
266
267 predContext.setPosition(i + 1);
268 predContext.setSize(nodes2FilterSize);
269 Object predResult = predicate.evaluate(predContext);
270 if (predResult instanceof Number) {
271
272
273 int proximity = ((Number) predResult).intValue();
274 if (proximity == (i + 1)) {
275 filteredNodes.add(contextNode);
276 }
277 }
278 else {
279 Boolean includes =
280 BooleanFunction.evaluate(predResult,
281 predContext.getNavigator());
282 if (includes.booleanValue()) {
283 filteredNodes.add(contextNode);
284 }
285 }
286 }
287 return filteredNodes;
288 }
289
290 }