Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
PredicateSet |
|
| 3.111111111111111;3.111 |
1 | /* | |
2 | * $Header: /home/projects/jaxen/scm/jaxen/src/java/main/org/jaxen/expr/PredicateSet.java,v 1.23 2006/11/13 22:38:17 elharo Exp $ | |
3 | * $Revision: 1.23 $ | |
4 | * $Date: 2006/11/13 22:38:17 $ | |
5 | * | |
6 | * ==================================================================== | |
7 | * | |
8 | * Copyright 2000-2002 bob mcwhirter & James Strachan. | |
9 | * All rights reserved. | |
10 | * | |
11 | * | |
12 | * Redistribution and use in source and binary forms, with or without | |
13 | * modification, are permitted provided that the following conditions are | |
14 | * met: | |
15 | * | |
16 | * * Redistributions of source code must retain the above copyright | |
17 | * notice, this list of conditions and the following disclaimer. | |
18 | * | |
19 | * * Redistributions in binary form must reproduce the above copyright | |
20 | * notice, this list of conditions and the following disclaimer in the | |
21 | * documentation and/or other materials provided with the distribution. | |
22 | * | |
23 | * * Neither the name of the Jaxen Project nor the names of its | |
24 | * contributors may be used to endorse or promote products derived | |
25 | * from this software without specific prior written permission. | |
26 | * | |
27 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS | |
28 | * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
29 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | |
30 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER | |
31 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
32 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
33 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
34 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
35 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
36 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
37 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
38 | * | |
39 | * ==================================================================== | |
40 | * This software consists of voluntary contributions made by many | |
41 | * individuals on behalf of the Jaxen Project and was originally | |
42 | * created by bob mcwhirter <bob@werken.com> and | |
43 | * James Strachan <jstrachan@apache.org>. For more information on the | |
44 | * Jaxen Project, please see <http://www.jaxen.org/>. | |
45 | * | |
46 | * $Id: PredicateSet.java,v 1.23 2006/11/13 22:38:17 elharo Exp $ | |
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 | 18680 | { |
88 | 18680 | this.predicates = Collections.EMPTY_LIST; |
89 | 18680 | } |
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 | 1356 | if ( this.predicates == Collections.EMPTY_LIST ) |
99 | { | |
100 | 1306 | this.predicates = new ArrayList(); |
101 | } | |
102 | ||
103 | 1356 | this.predicates.add( predicate ); |
104 | 1356 | } |
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 | 16154 | return this.predicates; |
115 | } | |
116 | ||
117 | /** | |
118 | * Simplify each of the predicates in the list. | |
119 | */ | |
120 | public void simplify() | |
121 | { | |
122 | 18516 | Iterator predIter = this.predicates.iterator(); |
123 | 18516 | Predicate eachPred = null; |
124 | ||
125 | 19854 | while ( predIter.hasNext() ) |
126 | { | |
127 | 1338 | eachPred = (Predicate) predIter.next(); |
128 | 1338 | eachPred.simplify(); |
129 | 1338 | } |
130 | 18516 | } |
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 | 3748 | StringBuffer buf = new StringBuffer(); |
140 | ||
141 | 3748 | Iterator predIter = this.predicates.iterator(); |
142 | 3748 | Predicate eachPred = null; |
143 | ||
144 | 4314 | while ( predIter.hasNext() ) |
145 | { | |
146 | 566 | eachPred = (Predicate) predIter.next(); |
147 | 566 | buf.append( eachPred.getText() ); |
148 | 566 | } |
149 | ||
150 | 3748 | 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 | 0 | return anyMatchingNode( contextNodeSet, support ); |
168 | } | |
169 | ||
170 | private boolean anyMatchingNode(List contextNodeSet, ContextSupport support) | |
171 | throws JaxenException { | |
172 | // Easy way out (necessary) | |
173 | 0 | if (predicates.size() == 0) { |
174 | 0 | return false; |
175 | } | |
176 | 0 | Iterator predIter = predicates.iterator(); |
177 | ||
178 | // initial list to filter | |
179 | 0 | List nodes2Filter = contextNodeSet; |
180 | // apply all predicates | |
181 | 0 | while(predIter.hasNext()) { |
182 | 0 | final int nodes2FilterSize = nodes2Filter.size(); |
183 | // Set up a dummy context with a list to hold each node | |
184 | 0 | Context predContext = new Context(support); |
185 | 0 | List tempList = new ArrayList(1); |
186 | 0 | predContext.setNodeSet(tempList); |
187 | // loop through the current nodes to filter and add to the | |
188 | // filtered nodes list if the predicate succeeds | |
189 | 0 | for (int i = 0; i < nodes2FilterSize; ++i) { |
190 | 0 | Object contextNode = nodes2Filter.get(i); |
191 | 0 | tempList.clear(); |
192 | 0 | tempList.add(contextNode); |
193 | 0 | predContext.setNodeSet(tempList); |
194 | // ???? | |
195 | 0 | predContext.setPosition(i + 1); |
196 | 0 | predContext.setSize(nodes2FilterSize); |
197 | 0 | Object predResult = ((Predicate)predIter.next()).evaluate(predContext); |
198 | 0 | if (predResult instanceof Number) { |
199 | // Here we assume nodes are in forward or reverse order | |
200 | // as appropriate for axis | |
201 | 0 | int proximity = ((Number) predResult).intValue(); |
202 | 0 | if (proximity == (i + 1)) { |
203 | 0 | return true; |
204 | } | |
205 | 0 | } |
206 | else { | |
207 | 0 | Boolean includes = |
208 | BooleanFunction.evaluate(predResult, | |
209 | predContext.getNavigator()); | |
210 | 0 | if (includes.booleanValue()) { |
211 | 0 | return true; |
212 | } | |
213 | } | |
214 | } | |
215 | 0 | } |
216 | ||
217 | 0 | 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 | // Easy way out (necessary) | |
235 | 18212 | if (predicates.size() == 0) { |
236 | 12800 | return contextNodeSet; |
237 | } | |
238 | 5412 | Iterator predIter = predicates.iterator(); |
239 | ||
240 | // initial list to filter | |
241 | 5412 | List nodes2Filter = contextNodeSet; |
242 | // apply all predicates | |
243 | 10846 | while(predIter.hasNext()) { |
244 | 5438 | nodes2Filter = |
245 | applyPredicate((Predicate)predIter.next(), nodes2Filter, support); | |
246 | 5434 | } |
247 | ||
248 | 5408 | return nodes2Filter; |
249 | } | |
250 | ||
251 | public List applyPredicate(Predicate predicate, List nodes2Filter, ContextSupport support) | |
252 | throws JaxenException { | |
253 | 5438 | final int nodes2FilterSize = nodes2Filter.size(); |
254 | 5438 | List filteredNodes = new ArrayList(nodes2FilterSize); |
255 | // Set up a dummy context with a list to hold each node | |
256 | 5438 | Context predContext = new Context(support); |
257 | 5438 | List tempList = new ArrayList(1); |
258 | 5438 | predContext.setNodeSet(tempList); |
259 | // loop through the current nodes to filter and add to the | |
260 | // filtered nodes list if the predicate succeeds | |
261 | 13316 | for (int i = 0; i < nodes2FilterSize; ++i) { |
262 | 7882 | Object contextNode = nodes2Filter.get(i); |
263 | 7882 | tempList.clear(); |
264 | 7882 | tempList.add(contextNode); |
265 | 7882 | predContext.setNodeSet(tempList); |
266 | // ???? | |
267 | 7882 | predContext.setPosition(i + 1); |
268 | 7882 | predContext.setSize(nodes2FilterSize); |
269 | 7882 | Object predResult = predicate.evaluate(predContext); |
270 | 7878 | if (predResult instanceof Number) { |
271 | // Here we assume nodes are in forward or reverse order | |
272 | // as appropriate for axis | |
273 | 1514 | int proximity = ((Number) predResult).intValue(); |
274 | 1514 | if (proximity == (i + 1)) { |
275 | 322 | filteredNodes.add(contextNode); |
276 | } | |
277 | 1514 | } |
278 | else { | |
279 | 6364 | Boolean includes = |
280 | BooleanFunction.evaluate(predResult, | |
281 | predContext.getNavigator()); | |
282 | 6364 | if (includes.booleanValue()) { |
283 | 980 | filteredNodes.add(contextNode); |
284 | } | |
285 | } | |
286 | } | |
287 | 5434 | return filteredNodes; |
288 | } | |
289 | ||
290 | } |