KickJava   Java API By Example, From Geeks To Geeks.

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


1 package com.icl.saxon.expr;
2 import com.icl.saxon.Context;
3 import com.icl.saxon.om.NodeEnumeration;
4 import com.icl.saxon.functions.Last;
5 import com.icl.saxon.functions.Position;
6
7 /**
8 * A FilterExpression contains a base expression and a filter predicate, which may be an
9 * integer expression (positional filter), or a boolean expression (qualifier)
10 */

11
12 class FilterExpression extends NodeSetExpression {
13
14     private Expression start;
15     private Expression filter;
16     private int dependencies = -1;
17
18     /**
19     * Constructor
20     * @param start A node-set expression denoting the absolute or relative set of nodes from which the
21     * navigation path should start.
22     * @param filter An expression defining the filter predicate
23     */

24
25     public FilterExpression(Expression start, Expression filter) {
26         this.start = start;
27         this.filter = filter;
28     }
29
30     /**
31     * Simplify an expression
32     */

33
34     public Expression simplify() throws XPathException {
35         
36         start = start.simplify();
37         filter = filter.simplify();
38         
39         // ignore the filter if the base expression is an empty node-set
40
if (start instanceof EmptyNodeSet) {
41             return start;
42         }
43
44         // check whether the filter is a constant true() or false()
45
if (filter instanceof Value && !(filter instanceof NumericValue)) {
46             boolean f = ((Value)filter).asBoolean();
47             if (f) {
48                 return start;
49             } else {
50                 return new EmptyNodeSet();
51             }
52         }
53
54         // check whether the filter is [last()] (note, position()=last() will
55
// have already been simplified)
56

57         if (filter instanceof Last) {
58             filter = new IsLastExpression(true);
59         }
60
61         // following code is designed to catch the case where we recurse over a node-set
62
// setting $ns := $ns[position()>1]. The effect is to combine the accumulating
63
// filters, for example on the third iteration the filter will be effectively
64
// x[position()>3] rather than x[position()>1][position()>1][position()>1].
65

66         if (start instanceof NodeSetIntent &&
67                 filter instanceof PositionRange) {
68             PositionRange pred = (PositionRange)filter;
69             if (pred.getMinPosition()==2 && pred.getMaxPosition()==Integer.MAX_VALUE) {
70                 //System.err.println("Found candidate ");
71
NodeSetIntent b = (NodeSetIntent)start;
72                 //System.err.println("Found candidate start is " + b.getNodeSetExpression().getClass());
73
if (b.getNodeSetExpression() instanceof FilterExpression) {
74                     FilterExpression t = (FilterExpression)b.getNodeSetExpression();
75                     if (t.filter instanceof PositionRange) {
76                         PositionRange pred2 = (PositionRange)t.filter;
77                         if (pred2.getMaxPosition()==Integer.MAX_VALUE) {
78                             //System.err.println("Opt!! start =" + pred2.getMinPosition() );
79
return new FilterExpression(t.start,
80                                             new PositionRange(pred2.getMinPosition()+1, Integer.MAX_VALUE));
81                         }
82                     }
83                 }
84             }
85         }
86         
87         return this;
88     }
89
90     /**
91     * Evaluate the filter expression in a given context to return a Node Enumeration
92     * @param context the evaluation context
93     * @param sort true if the result must be in document order
94     */

95
96     public NodeEnumeration enumerate(Context context, boolean sort) throws XPathException {
97
98         // if the expression references variables, or depends on other aspects
99
// of the XSLT context, then fix up these dependencies now. If the expression
100
// will only return nodes from the context document, then any dependency on
101
// the context document within the predicate can also be fixed up now.
102

103         int actualdep = getDependencies();
104         int removedep = 0;
105         
106         if ((actualdep & Context.XSLT_CONTEXT) != 0) {
107             removedep |= Context.XSLT_CONTEXT;
108         }
109         
110         if (start.isContextDocumentNodeSet() && ((actualdep & Context.CONTEXT_DOCUMENT) != 0)) {
111             removedep |= Context.CONTEXT_DOCUMENT;
112         }
113         
114         if (removedep != 0) {
115             return reduce(removedep, context).enumerate(context, sort);
116         }
117     
118         if (!sort) {
119             // the user didn't ask for document order, but we may need to do it anyway
120
if ( filter.getDataType()==Value.NUMBER ||
121                  filter.getDataType()==Value.ANY ||
122                  (filter.getDependencies() & (Context.POSITION|Context.LAST)) != 0 ) {
123                 sort = true;
124             }
125         }
126         
127         if (start instanceof SingletonNodeSet) {
128             if (!((SingletonNodeSet)start).isGeneralUseAllowed()) {
129                 throw new XPathException("To use a result tree fragment in a filter expression, either use exsl:node-set() or specify version='1.1'");
130             }
131         }
132
133         NodeEnumeration base = start.enumerate(context, sort);
134         if (!base.hasMoreElements()) {
135             return base; // quick exit for an empty node set
136
}
137
138         return new FilterEnumerator(base, filter, context, false);
139     }
140
141     /**
142     * Determine which aspects of the context the expression depends on. The result is
143     * a bitwise-or'ed value composed from constants such as Context.VARIABLES and
144     * Context.CURRENT_NODE
145     */

146
147     public int getDependencies() {
148         // not all dependencies in the filter expression matter, because the context node,
149
// position, and size are not dependent on the outer context.
150
if (dependencies==-1) {
151             dependencies = start.getDependencies() |
152                 (filter.getDependencies() & Context.XSLT_CONTEXT);
153         }
154         // System.err.println("Filter expression getDependencies() = " + dependencies);
155
return dependencies;
156     }
157
158     /**
159     * Perform a partial evaluation of the expression, by eliminating specified dependencies
160     * on the context.
161     * @param dep The dependencies to be removed
162     * @param context The context to be used for the partial evaluation
163     * @return a new expression that does not have any of the specified
164     * dependencies
165     */

166
167     public Expression reduce(int dep, Context context) throws XPathException {
168         if ((dep & getDependencies()) != 0) {
169             Expression newstart = start.reduce(dep, context);
170             Expression newfilter = filter.reduce(dep & Context.XSLT_CONTEXT, context);
171             Expression e = new FilterExpression(newstart, newfilter);
172             e.setStaticContext(getStaticContext());
173             return e.simplify();
174         } else {
175             return this;
176         }
177     }
178
179     /**
180     * Determine, in the case of an expression whose data type is Value.NODESET,
181     * whether all the nodes in the node-set are guaranteed to come from the same
182     * document as the context node. Used for optimization.
183     */

184     
185     public boolean isContextDocumentNodeSet() {
186         return start.isContextDocumentNodeSet();
187     }
188
189     /**
190     * Diagnostic print of expression structure
191     */

192     
193     public void display(int level) {
194         System.err.println(indent(level) + "filter");
195         start.display(level+1);
196         filter.display(level+1);
197     }
198
199 }
200
201
202
203 //
204
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
205
// you may not use this file except in compliance with the License. You may obtain a copy of the
206
// License at http://www.mozilla.org/MPL/
207
//
208
// Software distributed under the License is distributed on an "AS IS" basis,
209
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
210
// See the License for the specific language governing rights and limitations under the License.
211
//
212
// The Original Code is: all this file.
213
//
214
// The Initial Developer of the Original Code is
215
// Michael Kay of International Computers Limited (mhkay@iclway.co.uk).
216
//
217
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
218
//
219
// Contributor(s): none.
220
//
221
Popular Tags