KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > expr > FilterIterator


1 package net.sf.saxon.expr;
2 import net.sf.saxon.om.Item;
3 import net.sf.saxon.om.NodeInfo;
4 import net.sf.saxon.om.SequenceIterator;
5 import net.sf.saxon.trace.Location;
6 import net.sf.saxon.trans.XPathException;
7 import net.sf.saxon.value.*;
8
9 /**
10 * A FilterIterator filters an input sequence using a filter expression. Note that a FilterIterator
11 * is not used where the filter is a constant number (PositionFilter is used for this purpose instead),
12 * so this class does no optimizations for numeric predicates.
13 */

14
15 public class FilterIterator implements SequenceIterator {
16
17     protected SequenceIterator base;
18     protected Expression filter;
19     private int position = 0;
20     private Item current = null;
21     protected XPathContext filterContext;
22
23     /**
24     * Constructor
25     * @param base An iteration of the items to be filtered
26     * @param filter The expression defining the filter predicate
27     * @param context The context in which the expression is being evaluated
28     */

29
30     public FilterIterator(SequenceIterator base, Expression filter,
31                             XPathContext context) {
32         this.base = base;
33         this.filter = filter;
34         filterContext = context.newMinorContext();
35         filterContext.setCurrentIterator(base);
36         filterContext.setOriginatingConstructType(Location.FILTER_EXPRESSION);
37     }
38
39     /**
40     * Get the next item if there is one
41     */

42
43     public Item next() throws XPathException {
44         current = getNextMatchingItem();
45         if (current == null) {
46             position = -1;
47         } else {
48             position++;
49         }
50         return current;
51     }
52
53     /**
54     * Get the next node that matches the filter predicate if there is one,
55      * or null if not.
56     */

57
58     protected Item getNextMatchingItem() throws XPathException {
59         while (true) {
60             Item next = base.next();
61             if (next == null) {
62                 return null;
63             }
64             if (matches()) {
65                 return next;
66             }
67         }
68     }
69
70     /**
71     * Determine whether the context item matches the filter predicate
72     */

73
74     protected boolean matches() throws XPathException {
75
76         // This code is carefully designed to avoid reading more items from the
77
// iteration of the filter expression than are absolutely essential.
78

79         // The code is almost identical to the code in ExpressionTool#effectiveBooleanValue
80
// except for the handling of a numeric result
81

82         SequenceIterator iterator = filter.iterate(filterContext);
83         Item first = iterator.next();
84         if (first == null) {
85             return false;
86         }
87         if (first instanceof NodeInfo) {
88             return true;
89         } else {
90             if (first instanceof BooleanValue) {
91                 if (iterator.next() != null) {
92                     ExpressionTool.ebvError("sequence of two or more items starting with an atomic value");
93                 }
94                 return ((BooleanValue)first).getBooleanValue();
95             } else if (first instanceof StringValue) {
96                 if (iterator.next() != null) {
97                     ExpressionTool.ebvError("sequence of two or more items starting with an atomic value");
98                 }
99                 return (first.getStringValueCS().length()!=0);
100             } else if (first instanceof NumericValue) {
101                 if (iterator.next() != null) {
102                     ExpressionTool.ebvError("sequence of two or more items starting with an atomic value");
103                 }
104                 IntegerValue basePos = new IntegerValue(base.position());
105                 return first.equals(basePos);
106             } else {
107                 ExpressionTool.ebvError("sequence starting with an atomic value other than a boolean, number, or string");
108                 return false;
109             }
110         }
111     }
112
113     public Item current() {
114         return current;
115     }
116
117     public int position() {
118         return position;
119     }
120
121     /**
122     * Get another iterator to return the same nodes
123     */

124
125     public SequenceIterator getAnother() throws XPathException {
126         return new FilterIterator(base.getAnother(), filter,
127                                     filterContext);
128     }
129
130     /**
131      * Get properties of this iterator, as a bit-significant integer.
132      *
133      * @return the properties of this iterator. This will be some combination of
134      * properties such as {@link GROUNDED}, {@link LAST_POSITION_FINDER},
135      * and {@link LOOKAHEAD}. It is always
136      * acceptable to return the value zero, indicating that there are no known special properties.
137      * It is acceptable for the properties of the iterator to change depending on its state.
138      */

139
140     public int getProperties() {
141         return 0;
142     }
143
144     /**
145     * Subclass to handle the common special case where it is statically known
146     * that the filter cannot return a numeric value
147     */

148
149     public static final class NonNumeric extends FilterIterator {
150
151         public NonNumeric(SequenceIterator base, Expression filter,
152                             XPathContext context) {
153             super(base, filter, context);
154         }
155
156         /**
157         * Determine whether the context item matches the filter predicate
158         */

159
160         protected boolean matches() throws XPathException {
161             return filter.effectiveBooleanValue(filterContext);
162         }
163
164         /**
165         * Get another iterator to return the same nodes
166         */

167
168         public SequenceIterator getAnother() throws XPathException {
169             return new FilterIterator.NonNumeric(base.getAnother(), filter,
170                                         filterContext);
171         }
172     }
173
174     /**
175      * Subclass to support the extension function saxon:leading, which terminates
176      * the iteration at the first item whose predicate is false
177     */

178
179     public static final class Leading extends FilterIterator {
180
181         public Leading(SequenceIterator base, Expression filter,
182                             XPathContext context) {
183             super(base, filter, context);
184         }
185
186         /**
187         * Determine whether the context item matches the filter predicate
188         */

189
190         protected boolean matches() throws XPathException {
191             return filter.effectiveBooleanValue(filterContext);
192         }
193
194         /**
195         * Get the next node that matches the filter predicate if there is one
196         */

197
198         protected Item getNextMatchingItem() throws XPathException {
199             while (true) {
200                 Item next = base.next();
201                 if (next == null) {
202                     return null;
203                 }
204                 if (matches()) {
205                     return next;
206                 } else {
207                     // terminate the iteration on the first non-match
208
return null;
209                 }
210             }
211         }
212
213         /**
214         * Get another iterator to return the same nodes
215         */

216
217         public SequenceIterator getAnother() throws XPathException {
218             return new FilterIterator.Leading(base.getAnother(), filter,
219                                         filterContext);
220         }
221
222
223     }
224
225
226 }
227
228
229
230 //
231
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
232
// you may not use this file except in compliance with the License. You may obtain a copy of the
233
// License at http://www.mozilla.org/MPL/
234
//
235
// Software distributed under the License is distributed on an "AS IS" basis,
236
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
237
// See the License for the specific language governing rights and limitations under the License.
238
//
239
// The Original Code is: all this file.
240
//
241
// The Initial Developer of the Original Code is Michael H. Kay.
242
//
243
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
244
//
245
// Contributor(s): none.
246
//
247
Popular Tags