KickJava   Java API By Example, From Geeks To Geeks.

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


1 package com.icl.saxon.expr;
2 import com.icl.saxon.Context;
3 import com.icl.saxon.functions.*;
4
5
6 /**
7 * Relational Expression: a boolean expression that compares two expressions
8 * for equals, not-equals, greater-than or less-than.
9 */

10
11 final class RelationalExpression extends BinaryExpression {
12
13     /**
14     * Default constructor
15     */

16
17     public RelationalExpression(){};
18
19     /**
20     * Create a relational expression identifying the two operands and the operator
21     * @param p1 the left-hand operand
22     * @param op the operator, as a token returned by the Tokenizer (e.g. Tokenizer.LT)
23     * @param p2 the right-hand operand
24     */

25
26     public RelationalExpression(Expression p1, int op, Expression p2) {
27         super(p1, op, p2);
28     }
29
30     /**
31     * Simplify an expression
32     * @return the simplified expression
33     */

34
35     public Expression simplify() throws XPathException {
36
37         p1 = p1.simplify();
38         p2 = p2.simplify();
39         
40         // detect common case such as @att='x'
41

42         if (p1 instanceof SingletonExpression &&
43                 (p2 instanceof StringValue ||
44                  p2 instanceof NumericValue ||
45                  p2 instanceof FragmentValue ||
46                  p2 instanceof TextFragmentValue )) {
47
48             Expression s = new SingletonComparison((SingletonExpression)p1, operator, (Value)p2);
49             s.setStaticContext(getStaticContext());
50             return s;
51         }
52
53         if (p2 instanceof SingletonExpression &&
54                 (p1 instanceof StringValue ||
55                  p1 instanceof NumericValue ||
56                  p1 instanceof FragmentValue ||
57                  p1 instanceof TextFragmentValue )) {
58
59             Expression s = new SingletonComparison((SingletonExpression)p2,
60                                              Value.inverse(operator), (Value)p1);
61             s.setStaticContext(getStaticContext());
62             return s;
63         }
64         
65         // detect common case such as [element='string']
66

67         if (p1 instanceof NodeSetExpression &&
68                 (p2 instanceof StringValue ||
69                  p2 instanceof NumericValue ||
70                  p2 instanceof FragmentValue ||
71                  p2 instanceof TextFragmentValue )) {
72
73             Expression s = new NodeSetComparison((NodeSetExpression)p1, operator, (Value)p2);
74             s.setStaticContext(getStaticContext());
75             return s;
76         }
77
78         if (p2 instanceof NodeSetExpression &&
79                 (p1 instanceof StringValue ||
80                  p1 instanceof NumericValue ||
81                  p1 instanceof FragmentValue ||
82                  p1 instanceof TextFragmentValue )) {
83
84             Expression s = new NodeSetComparison((NodeSetExpression)p2,
85                                              Value.inverse(operator), (Value)p1);
86             s.setStaticContext(getStaticContext());
87             return s;
88         }
89
90         // evaluate the expression now if both arguments are constant
91

92         if ((p1 instanceof Value) && (p2 instanceof Value)) {
93             return evaluate(null);
94         }
95         
96         // optimise count(x) = 0 (or >0, !=0, etc)
97

98         if ((p1 instanceof Count) && (((Count)p1).getNumberOfArguments()==1) &&
99                 (((Count)p1).argument[0].getDataType()==Value.NODESET) &&
100                 (p2 instanceof NumericValue) && (((Value)p2).asNumber()==0)) {
101             if (operator == Tokenizer.EQUALS || operator == Tokenizer.LE) {
102                 // rewrite count(x)=0 as not(x)
103
Not fn = new Not();
104                 fn.addArgument(((Count)p1).argument[0]);
105                 fn.setStaticContext(getStaticContext());
106                 return fn;
107             } else if (operator == Tokenizer.NE || operator == Tokenizer.GT) {
108                 // rewrite count(x)!=0, count(x)>0 as boolean(x)
109
BooleanFn fn = new BooleanFn();
110                 fn.addArgument(((Count)p1).argument[0]);
111                 fn.setStaticContext(getStaticContext());
112                 return fn;
113             } else if (operator == Tokenizer.GE) {
114                 // rewrite count(x)>=0 as true()
115
return new BooleanValue(true);
116             } else { // operator == Tokenizer.LT
117
// rewrite count(x)<0 as false()
118
return new BooleanValue(false);
119             }
120         }
121         
122         // optimise (0 = count(x)), etc
123

124         if ((p2 instanceof Count) &&
125              (p1 instanceof NumericValue) && (((Value)p1).asNumber()==0)) {
126             Expression s = new RelationalExpression(p2, Value.inverse(operator), p1).simplify();
127             s.setStaticContext(getStaticContext());
128             return s;
129         }
130
131         // optimise string-length(x) = 0, >0, !=0 etc
132

133         if ((p1 instanceof StringLength) &&
134                 (((StringLength)p1).getNumberOfArguments()==1) &&
135                 (p2 instanceof NumericValue) && (((Value)p2).asNumber()==0)) {
136             
137             // force conversion of argument to a string
138
Expression arg = ((StringLength)p1).argument[0];
139             if (!(arg instanceof StringValue)) {
140                 StringFn fn = new StringFn();
141                 fn.addArgument(arg);
142                 arg = fn;
143             }
144             
145             if (operator == Tokenizer.EQUALS || operator == Tokenizer.LE) {
146                 // rewrite string-length(x)=0 as not(string(x))
147
Not fn = new Not();
148                 fn.addArgument(arg);
149                 fn.setStaticContext(getStaticContext());
150                 return fn;
151             } else if (operator == Tokenizer.GT || operator == Tokenizer.NE) {
152                 // rewrite string-length(x)!=0 or >0 as boolean(string(x))
153
BooleanFn fn = new BooleanFn();
154                 fn.addArgument(arg);
155                 fn.setStaticContext(getStaticContext());
156                 return fn;
157             } else if (operator == Tokenizer.GE) {
158                 // rewrite string-length(x)>=0 as true()
159
return new BooleanValue(true);
160             } else /* if (operator == Tokenizer.LT) */ {
161                 // rewrite string-length(x)<0 as false()
162
return new BooleanValue(false);
163             }
164         }
165
166         // optimise (0 = string-length(x)), etc
167

168         if ((p2 instanceof StringLength) &&
169              (p1 instanceof NumericValue) && (((Value)p1).asNumber()==0)) {
170             Expression s = new RelationalExpression(p2, Value.inverse(operator), p1).simplify();
171             s.setStaticContext(getStaticContext());
172             return s;
173         }
174         
175         // optimise [position() < n] etc
176

177         if ((p1 instanceof Position) && (p2 instanceof NumericValue)) {
178             double pos = ((NumericValue)p2).asNumber();
179             switch (operator) {
180                 case Tokenizer.EQUALS:
181                     return new PositionRange((int)pos, (int)pos);
182                 case Tokenizer.GE:
183                     return new PositionRange((int)pos, Integer.MAX_VALUE);
184                 case Tokenizer.NE:
185                     break;
186                 case Tokenizer.LT:
187                     return new PositionRange(1, (int)Math.floor(pos - 0.00000000001) );
188                 case Tokenizer.GT:
189                     return new PositionRange((int)Math.ceil(pos + 0.00000000001), Integer.MAX_VALUE);
190                 case Tokenizer.LE:
191                     return new PositionRange(1, ((int)pos));
192             }
193         }
194         if ((p1 instanceof NumericValue) && (p2 instanceof Position)) {
195             double pos = ((NumericValue)p1).asNumber();
196             switch (operator) {
197                 case Tokenizer.EQUALS:
198                     return new PositionRange((int)pos, (int)pos);
199                 case Tokenizer.LE:
200                     return new PositionRange((int)pos, Integer.MAX_VALUE);
201                 case Tokenizer.NE:
202                     break;
203                 case Tokenizer.GT:
204                     return new PositionRange(1, (int)Math.floor(pos - 0.00000000001) );
205                 case Tokenizer.LT:
206                     return new PositionRange((int)Math.ceil(pos + 0.00000000001), Integer.MAX_VALUE);
207                 case Tokenizer.GE:
208                     return new PositionRange(1, (int)pos);
209             }
210         }
211         
212         // optimise [position()=last()] etc
213

214         if ((p1 instanceof Position) && (p2 instanceof Last)) {
215             switch (operator) {
216                 case Tokenizer.EQUALS:
217                 case Tokenizer.GE:
218                     return new IsLastExpression(true);
219                 case Tokenizer.NE:
220                 case Tokenizer.LT:
221                     return new IsLastExpression(false);
222                 case Tokenizer.GT:
223                     return new BooleanValue(false);
224                 case Tokenizer.LE:
225                     return new BooleanValue(true);
226             }
227         }
228         if ((p1 instanceof Last) && (p2 instanceof Position)) {
229             switch (operator) {
230                 case Tokenizer.EQUALS:
231                 case Tokenizer.LE:
232                     return new IsLastExpression(true);
233                 case Tokenizer.NE:
234                 case Tokenizer.GT:
235                     return new IsLastExpression(false);
236                 case Tokenizer.LT:
237                     return new BooleanValue(false);
238                 case Tokenizer.GE:
239                     return new BooleanValue(true);
240             }
241         }
242         return this;
243     }
244
245     /**
246     * Evaluate the expression in a given context
247     * @param c the given context for evaluation
248     * @return a BooleanValue representing the result of the numeric comparison of the two operands
249     */

250
251     public Value evaluate(Context c) throws XPathException {
252         return new BooleanValue(evaluateAsBoolean(c));
253     }
254
255     /**
256     * Evaluate the expression in a given context
257     * @param c the given context for evaluation
258     * @return a boolean representing the result of the numeric comparison of the two operands
259     */

260
261     public boolean evaluateAsBoolean(Context c) throws XPathException {
262         Value s1 = p1.evaluate(c);
263         Value s2 = p2.evaluate(c);
264         return s1.compare(operator, s2);
265     }
266
267     /**
268     * Determine the data type of the expression
269     * @return Value.BOOLEAN
270     */

271
272     public int getDataType() {
273         return Value.BOOLEAN;
274     }
275
276     /**
277     * Perform a partial evaluation of the expression, by eliminating specified dependencies
278     * on the context.
279     * @param dependencies The dependencies to be removed
280     * @param context The context to be used for the partial evaluation
281     * @return a new expression that does not have any of the specified
282     * dependencies
283     */

284
285     public Expression reduce(int dependencies, Context context) throws XPathException {
286
287         if ((getDependencies() & dependencies) != 0 ) {
288             Expression e = new RelationalExpression(
289                                 p1.reduce(dependencies, context),
290                                 operator,
291                                 p2.reduce(dependencies, context));
292             e.setStaticContext(getStaticContext());
293             return e.simplify();
294         } else {
295             return this;
296         }
297     }
298
299
300 }
301
302 //
303
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
304
// you may not use this file except in compliance with the License. You may obtain a copy of the
305
// License at http://www.mozilla.org/MPL/
306
//
307
// Software distributed under the License is distributed on an "AS IS" basis,
308
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
309
// See the License for the specific language governing rights and limitations under the License.
310
//
311
// The Original Code is: all this file.
312
//
313
// The Initial Developer of the Original Code is
314
// Michael Kay of International Computers Limited (mhkay@iclway.co.uk).
315
//
316
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
317
//
318
// Contributor(s): none.
319
//
320
Popular Tags