KickJava   Java API By Example, From Geeks To Geeks.

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


1 package net.sf.saxon.expr;
2 import net.sf.saxon.functions.NumberFn;
3 import net.sf.saxon.om.Item;
4 import net.sf.saxon.om.SequenceIterator;
5 import net.sf.saxon.sort.AtomicComparer;
6 import net.sf.saxon.sort.CodepointCollator;
7 import net.sf.saxon.trans.DynamicError;
8 import net.sf.saxon.trans.XPathException;
9 import net.sf.saxon.type.AtomicType;
10 import net.sf.saxon.type.ItemType;
11 import net.sf.saxon.type.Type;
12 import net.sf.saxon.value.*;
13
14 import java.util.ArrayList JavaDoc;
15 import java.util.Comparator JavaDoc;
16 import java.util.Iterator JavaDoc;
17 import java.util.List JavaDoc;
18
19 /**
20  * GeneralComparison10: a boolean expression that compares two expressions
21  * for equals, not-equals, greater-than or less-than. This implements the operators
22  * =, !=, <, >, etc. This version of the class implements general comparisons
23  * in XPath 1.0 backwards compatibility mode, as defined in the Oct 2004 revision
24  * of the specifications.
25 */

26
27 public class GeneralComparison10 extends BinaryExpression {
28
29     protected int singletonOperator;
30     protected AtomicComparer comparer;
31     private boolean atomize0 = true;
32     private boolean atomize1 = true;
33     private boolean maybeBoolean0 = true;
34     private boolean maybeBoolean1 = true;
35
36     /**
37     * Create a general comparison identifying the two operands and the operator
38     * @param p0 the left-hand operand
39     * @param op the operator, as a token returned by the Tokenizer (e.g. Token.LT)
40     * @param p1 the right-hand operand
41     */

42
43     public GeneralComparison10(Expression p0, int op, Expression p1) {
44         super(p0, op, p1);
45         singletonOperator = getSingletonOperator(op);
46     }
47
48     /**
49     * Determine the static cardinality. Returns [1..1]
50     */

51
52     public int computeCardinality() {
53         return StaticProperty.EXACTLY_ONE;
54     }
55
56     /**
57     * Type-check the expression
58     * @return the checked expression
59     */

60
61     public Expression typeCheck(StaticContext env, ItemType contextItemType) throws XPathException {
62
63         operand0 = operand0.typeCheck(env, contextItemType);
64         operand1 = operand1.typeCheck(env, contextItemType);
65
66         Comparator JavaDoc comp = env.getCollation(env.getDefaultCollationName());
67         if (comp==null) comp = CodepointCollator.getInstance();
68         comparer = new AtomicComparer(comp, env.getConfiguration());
69
70         return this;
71     }
72
73     /**
74     * Optimize the expression
75     * @return the checked expression
76     */

77
78     public Expression optimize(Optimizer opt, StaticContext env, ItemType contextItemType) throws XPathException {
79
80         operand0 = operand0.optimize(opt, env, contextItemType);
81         operand1 = operand1.optimize(opt, env, contextItemType);
82
83         // Neither operand needs to be sorted
84

85         operand0 = ExpressionTool.unsorted(opt, operand0, false);
86         operand1 = ExpressionTool.unsorted(opt, operand1, false);
87
88         // evaluate the expression now if both arguments are constant
89

90         if ((operand0 instanceof Value) && (operand1 instanceof Value)) {
91             return (AtomicValue)evaluateItem(null);
92         }
93
94         ItemType type0 = operand0.getItemType();
95         ItemType type1 = operand1.getItemType();
96
97         if (type0 instanceof AtomicType) {
98             atomize0 = false;
99         }
100         if (type1 instanceof AtomicType) {
101             atomize1 = false;
102         }
103
104         if (Type.relationship(type0, Type.BOOLEAN_TYPE) == Type.DISJOINT) {
105             maybeBoolean0 = false;
106         }
107         if (Type.relationship(type1, Type.BOOLEAN_TYPE) == Type.DISJOINT) {
108             maybeBoolean1 = false;
109         }
110
111         if (!maybeBoolean0 && !maybeBoolean1) {
112             int n0 = Type.relationship(type0, Type.NUMBER_TYPE);
113             int n1 = Type.relationship(type1, Type.NUMBER_TYPE);
114             boolean maybeNumeric0 = (n0 != Type.DISJOINT);
115             boolean maybeNumeric1 = (n1 != Type.DISJOINT);
116             boolean numeric0 = (n0 == Type.SUBSUMED_BY || n0 == Type.SAME_TYPE);
117             boolean numeric1 = (n1 == Type.SUBSUMED_BY || n1 == Type.SAME_TYPE);
118
119             // Use the 2.0 path if we don't have to deal with the possibility of boolean values,
120
// or the complications of converting values to numbers
121
if (!maybeNumeric0 && !maybeNumeric1) {
122                 return new GeneralComparison(operand0, operator, operand1)
123                         .typeCheck(env, contextItemType).optimize(opt, env, contextItemType);
124             }
125             if (numeric0 && numeric1) {
126                 return new GeneralComparison(operand0, operator, operand1)
127                         .typeCheck(env, contextItemType).optimize(opt, env, contextItemType);
128             }
129         }
130
131         return this;
132     }
133
134
135
136     /**
137     * Evaluate the expression in a given context
138     * @param context the given context for evaluation
139     * @return a BooleanValue representing the result of the numeric comparison of the two operands
140     */

141
142     public Item evaluateItem(XPathContext context) throws XPathException {
143         return BooleanValue.get(effectiveBooleanValue(context));
144     }
145
146     /**
147     * Evaluate the expression in a boolean context
148     * @param context the given context for evaluation
149     * @return a boolean representing the result of the numeric comparison of the two operands
150     */

151
152     public boolean effectiveBooleanValue(XPathContext context) throws XPathException {
153
154         // If the first operand is a singleton boolean,
155
// compare it with the effective boolean value of the other operand
156

157         SequenceIterator iter0 = null;
158
159         if (maybeBoolean0) {
160             iter0 = operand0.iterate(context);
161             Item i01 = iter0.next();
162             Item i02 = (i01 == null ? null : iter0.next());
163             if (i01 instanceof BooleanValue && i02 == null) {
164                 boolean b = operand1.effectiveBooleanValue(context);
165                 return compare((BooleanValue)i01, singletonOperator, BooleanValue.get(b), comparer, context);
166             }
167             if (i01 == null && !maybeBoolean1) {
168                 return false;
169             }
170         }
171
172         // If the second operand is a singleton boolean,
173
// compare it with the effective boolean value of the other operand
174

175         SequenceIterator iter1 = null;
176
177         if (maybeBoolean1) {
178             iter1 = operand1.iterate(context);
179             Item i11 = iter1.next();
180             Item i12 = (i11 == null ? null : iter1.next());
181             if (i11 instanceof BooleanValue && i12 == null) {
182                 boolean b = operand0.effectiveBooleanValue(context);
183                 return compare(BooleanValue.get(b), singletonOperator, (BooleanValue)i11, comparer, context);
184             }
185             if (i11 == null && !maybeBoolean0) {
186                 return false;
187             }
188         }
189
190         // Atomize both operands where necessary
191

192         if (iter0 == null) {
193             iter0 = operand0.iterate(context);
194         } else {
195             iter0 = iter0.getAnother();
196         }
197
198         if (iter1 == null) {
199             iter1 = operand1.iterate(context);
200         } else {
201             iter1 = iter1.getAnother();
202         }
203
204         if (atomize0) {
205             iter0 = Atomizer.AtomizingFunction.getAtomizingIterator(iter0);
206         }
207
208         if (atomize1) {
209             iter1 = Atomizer.AtomizingFunction.getAtomizingIterator(iter1);
210         }
211
212         // If the operator is one of <, >, <=, >=, then convert both operands to sequences of xs:double
213
// using the number() function
214

215         if (operator == Token.LT || operator == Token.LE || operator == Token.GT || operator == Token.GE) {
216             iter0 = new MappingIterator(iter0, new NumberFn(), null);
217             iter1 = new MappingIterator(iter1, new NumberFn(), null);
218         }
219
220         // Compare all pairs of atomic values in the two atomized sequences
221

222         List JavaDoc seq1 = null;
223         while (true) {
224             AtomicValue item0 = (AtomicValue)iter0.next();
225             if (item0 == null) {
226                 return false;
227             }
228             if (iter1 != null) {
229                 while (true) {
230                     AtomicValue item1 = (AtomicValue)iter1.next();
231                     if (item1 == null) {
232                         iter1 = null;
233                         if (seq1 == null) {
234                             // second operand is empty
235
return false;
236                         }
237                         break;
238                     }
239                     try {
240                         if (compare(item0, singletonOperator, item1, comparer, context)) {
241                             return true;
242                         }
243                         if (seq1 == null) {
244                             seq1 = new ArrayList JavaDoc(40);
245                         }
246                         seq1.add(item1);
247                     } catch (DynamicError e) {
248                         // re-throw the exception with location information added
249
if (e.getXPathContext() == null) {
250                             e.setXPathContext(context);
251                         }
252                         if (e.getLocator() == null) {
253                             e.setLocator(this);
254                         }
255                         throw e;
256                     }
257                 }
258             } else {
259                 Iterator listIter1 = seq1.iterator();
260                 while (listIter1.hasNext()) {
261                     AtomicValue item1 = (AtomicValue)listIter1.next();
262                     if (compare(item0, singletonOperator, item1, comparer, context)) {
263                         return true;
264                     }
265                 }
266             }
267         }
268     }
269
270     /**
271     * Compare two atomic values
272     */

273
274     protected static boolean compare(AtomicValue a0,
275                                      int operator,
276                                      AtomicValue a1,
277                                      AtomicComparer comparer,
278                                      XPathContext context) throws XPathException {
279
280         AtomicType t0 = (AtomicType)a0.getItemType().getPrimitiveItemType();
281         AtomicType t1 = (AtomicType)a1.getItemType().getPrimitiveItemType();
282
283         // If either operand is a number, convert both operands to xs:double using
284
// the rules of the number() function, and compare them
285

286         if (Type.isNumericPrimitiveType(t0) || Type.isNumericPrimitiveType(t1)) {
287             DoubleValue v0 = NumberFn.convert(a0);
288             DoubleValue v1 = NumberFn.convert(a1);
289             return ValueComparison.compare(v0, operator, v1, comparer);
290         }
291
292         // If either operand is a string, or if both are untyped atomic, convert
293
// both operands to strings and compare them
294

295         if (t0 == Type.STRING_TYPE || t1 == Type.STRING_TYPE ||
296                 (t0 == Type.UNTYPED_ATOMIC_TYPE && t1 == Type.UNTYPED_ATOMIC_TYPE)) {
297             StringValue s0 = (StringValue)a0.convert(Type.STRING, context);
298             StringValue s1 = (StringValue)a1.convert(Type.STRING, context);
299             return ValueComparison.compare(s0, operator, s1, comparer);
300         }
301
302         // If either operand is untyped atomic,
303
// convert it to the type of the other operand, and compare
304

305         if (t0 == Type.UNTYPED_ATOMIC_TYPE) {
306             a0 = a0.convert(t1, context, true);
307             if (a0 instanceof ValidationErrorValue) {
308                 throw ((ValidationErrorValue)a0).getException();
309             }
310         }
311
312         if (t1 == Type.UNTYPED_ATOMIC_TYPE) {
313             a1 = a1.convert(t0, context, true);
314             if (a1 instanceof ValidationErrorValue) {
315                 throw ((ValidationErrorValue)a1).getException();
316             }
317         }
318
319         return ValueComparison.compare(a0, operator, a1, comparer);
320     }
321
322     /**
323     * Determine the data type of the expression
324     * @return Type.BOOLEAN
325     */

326
327     public ItemType getItemType() {
328         return Type.BOOLEAN_TYPE;
329     }
330
331     /**
332     * Return the singleton form of the comparison operator, e.g. FEQ for EQUALS, FGT for GT
333     */

334
335     private static int getSingletonOperator(int op) {
336         switch (op) {
337             case Token.EQUALS:
338                 return Token.FEQ;
339             case Token.GE:
340                 return Token.FGE;
341             case Token.NE:
342                 return Token.FNE;
343             case Token.LT:
344                 return Token.FLT;
345             case Token.GT:
346                 return Token.FGT;
347             case Token.LE:
348                 return Token.FLE;
349             default:
350                 return op;
351         }
352     }
353
354     protected String JavaDoc displayOperator() {
355         return "many-to-many (1.0) " + super.displayOperator();
356     }
357
358 }
359
360 //
361
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
362
// you may not use this file except in compliance with the License. You may obtain a copy of the
363
// License at http://www.mozilla.org/MPL/
364
//
365
// Software distributed under the License is distributed on an "AS IS" basis,
366
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
367
// See the License for the specific language governing rights and limitations under the License.
368
//
369
// The Original Code is: all this file.
370
//
371
// The Initial Developer of the Original Code is Michael H. Kay.
372
//
373
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
374
//
375
// Contributor(s): none.
376
//
377
Popular Tags