KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > icl > saxon > expr > FilterEnumerator


1 package com.icl.saxon.expr;
2 import com.icl.saxon.*;
3 import com.icl.saxon.om.*;
4 import com.icl.saxon.functions.*;
5
6 import java.util.*;
7 import java.lang.Math JavaDoc;
8
9 /**
10 * A FilterEnumerator filters an input NodeEnumeration using a filter expression.
11 * The complication is that on request, it must determine the value of the last() position,
12 * which requires a lookahead.
13 */

14
15 public class FilterEnumerator implements NodeEnumeration {
16
17     private NodeEnumeration base;
18     private Expression filter;
19     private int position = 0;
20     private int last = -1;
21     int min = 1;
22     int max = Integer.MAX_VALUE;
23     private NodeInfo current = null;
24     private Context filterContext;
25     private int dataType = Value.ANY; // data type of filter expression
26
private boolean positional = false;
27     private boolean finished = false; // allows early finish with a numeric filter
28
private boolean finishAfterReject = false;
29                                            // causes enumeration to terminate the first
30
// time the predicate is false
31

32     /**
33     * Constructor
34     * @param base A node-set expression denoting the absolute or relative set of nodes from which the
35     * navigation path should start.
36     * @param filter The expression defining the filter predicate
37     * @param context The context in which the expression is being evaluated
38     * @param finishAfterReject: terminate enumeration on first failure
39     */

40
41     public FilterEnumerator(NodeEnumeration base, Expression filter,
42                             Context context, boolean finishAfterReject) throws XPathException {
43         this.base = base;
44         this.filter = filter;
45         this.finishAfterReject = finishAfterReject;
46
47         filterContext = context.newContext();
48
49         this.dataType = filter.getDataType();
50         
51         if (filter instanceof NumericValue) {
52             // if value is not an integer, it will never match
53
double pos = ((NumericValue)filter).asNumber();
54             if (Math.floor(pos)==pos) {
55                 min = (int)pos;
56                 max = min;
57                 positional = true;
58             } else {
59                 finished = true;
60             }
61         } else if (filter instanceof PositionRange) {
62             min = ((PositionRange)filter).getMinPosition();
63             max = ((PositionRange)filter).getMaxPosition();
64             positional = true;
65         }
66
67         if (base instanceof LastPositionFinder) {
68             filterContext.setLastPositionFinder((LastPositionFinder)base);
69         } else {
70             // TODO: only need to do this if last() is used in the predicate
71
this.base = new LookaheadEnumerator(base);
72             filterContext.setLastPositionFinder((LastPositionFinder)this.base);
73         }
74
75         current = getNextMatchingElement();
76     }
77
78     /**
79     * Test whether there are any more nodes available in the enumeration
80     */

81
82     public boolean hasMoreElements() {
83         if (finished) return false;
84         return current!=null;
85     }
86
87     /**
88     * Get the next node if there is one
89     */

90
91     public NodeInfo nextElement() throws XPathException {
92         NodeInfo node = current;
93         current = getNextMatchingElement();
94         return node;
95     }
96
97     /**
98     * Get the next node that matches the filter predicate if there is one
99     */

100
101     private NodeInfo getNextMatchingElement() throws XPathException {
102         while (!finished && base.hasMoreElements()) {
103             NodeInfo next = base.nextElement();
104             position++;
105             if (matches(next)) {
106                 return next;
107             } else if (finishAfterReject) {
108                 return null;
109             }
110         }
111         return null;
112     }
113
114     /**
115     * Determine whether a node matches the filter predicate
116     */

117
118     private boolean matches(NodeInfo node) throws XPathException {
119         if (positional) {
120             if (position<min) {
121                 return false;
122             } else if (position>max) {
123                 finished = true;
124                 return false;
125             } else {
126                 return true;
127             }
128         }
129         filterContext.setPosition(position);
130         filterContext.setContextNode(node);
131
132         // If the data type is known at compile time, and cannot be numeric,
133
// evaluate the expression directly as a boolean. This avoids expanding
134
// a node-set unnecessarily.
135

136         if (dataType==Value.NUMBER) {
137             double req = (int)filter.evaluateAsNumber(filterContext);
138             if ((double)position==req) {
139                 return true;
140             } else {
141                 return false;
142             }
143         } else if (dataType==Value.ANY) {
144             // have to determine the data type at run-time
145
Value val = filter.evaluate(filterContext);
146             if (val instanceof NumericValue) {
147                 return ((double)position==val.asNumber());
148             } else {
149                 return val.asBoolean();
150             }
151         } else {
152             // for any other type, evaluate the filter expression as a boolean
153
return filter.evaluateAsBoolean(filterContext);
154         }
155     }
156
157     /**
158     * Determine whether the nodes are guaranteed to be in document order
159     */

160
161     public boolean isSorted() {
162         return base.isSorted();
163     }
164
165     public boolean isReverseSorted() {
166         return base.isReverseSorted();
167     }
168
169     /**
170     * Determine whether the nodes are guaranteed to be peers
171     */

172
173     public boolean isPeer() {
174         return base.isPeer();
175     }
176 }
177
178
179
180 //
181
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
182
// you may not use this file except in compliance with the License. You may obtain a copy of the
183
// License at http://www.mozilla.org/MPL/
184
//
185
// Software distributed under the License is distributed on an "AS IS" basis,
186
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
187
// See the License for the specific language governing rights and limitations under the License.
188
//
189
// The Original Code is: all this file.
190
//
191
// The Initial Developer of the Original Code is
192
// Michael Kay of International Computers Limited (mhkay@iclway.co.uk).
193
//
194
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
195
//
196
// Contributor(s): none.
197
//
198
Popular Tags