2 // XQueryComparisonOperator.cs
\r
5 // Atsushi Enomoto <atsushi@ximian.com>
\r
8 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
\r
10 // Permission is hereby granted, free of charge, to any person obtaining
\r
11 // a copy of this software and associated documentation files (the
\r
12 // "Software"), to deal in the Software without restriction, including
\r
13 // without limitation the rights to use, copy, modify, merge, publish,
\r
14 // distribute, sublicense, and/or sell copies of the Software, and to
\r
15 // permit persons to whom the Software is furnished to do so, subject to
\r
16 // the following conditions:
\r
18 // The above copyright notice and this permission notice shall be
\r
19 // included in all copies or substantial portions of the Software.
\r
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\r
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\r
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
\r
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
\r
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
\r
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
\r
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
32 using System.Collections;
\r
33 using System.Reflection;
\r
35 using System.Xml.Schema;
\r
36 using System.Xml.Query;
\r
37 using System.Xml.XPath;
\r
38 using System.Xml.Xsl;
\r
40 namespace Mono.Xml.XPath2
\r
42 // FIXME: Handle complete type promotion and subtype substitution.
\r
43 // See XQuery 1.0 Appendix B.*.
\r
44 public class XQueryComparisonOperator
\r
46 private static bool OpBooleanLessThan (bool b1, bool b2)
\r
51 private static bool OpBooleanGreaterThan (bool b1, bool b2)
\r
56 private static bool CompareEquality (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
\r
58 switch (lvalue.XmlType.TypeCode) {
\r
59 case XmlTypeCode.Boolean:
\r
60 return lvalue.ValueAsBoolean == rvalue.ValueAsBoolean;
\r
61 case XmlTypeCode.String:
\r
62 return lvalue.Value == rvalue.Value;
\r
63 case XmlTypeCode.Date:
\r
64 case XmlTypeCode.Time:
\r
65 case XmlTypeCode.DateTime:
\r
66 case XmlTypeCode.YearMonthDuration:
\r
67 case XmlTypeCode.DayTimeDuration:
\r
68 return lvalue.ValueAsDateTime == rvalue.ValueAsDateTime;
\r
69 case XmlTypeCode.HexBinary:
\r
70 case XmlTypeCode.Base64Binary:
\r
71 case XmlTypeCode.AnyUri:
\r
72 case XmlTypeCode.QName:
\r
73 case XmlTypeCode.Notation:
\r
74 throw new NotImplementedException ();
\r
76 throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
\r
79 public static bool ValueEQ (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
\r
81 switch (lvalue.XmlType.TypeCode) {
\r
82 case XmlTypeCode.Decimal:
\r
83 if (rvalue.XmlType.TypeCode == XmlTypeCode.Decimal)
\r
84 return lvalue.ValueAsDecimal == rvalue.ValueAsDecimal;
\r
85 goto case XmlTypeCode.Integer;
\r
88 case XmlTypeCode.Integer:
\r
89 case XmlTypeCode.Float:
\r
90 case XmlTypeCode.Double:
\r
91 switch (rvalue.XmlType.TypeCode) {
\r
92 case XmlTypeCode.Integer:
\r
93 case XmlTypeCode.Decimal:
\r
94 case XmlTypeCode.Float:
\r
95 case XmlTypeCode.Double:
\r
96 return lvalue.ValueAsDouble == rvalue.ValueAsDouble;
\r
100 // FIXME: handle Gregorian (gXXX) types
\r
104 if (lvalue.XmlType.TypeCode != rvalue.XmlType.TypeCode)
\r
105 return CompareEquality (lvalue, rvalue);
\r
108 throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
\r
111 public static bool ValueNE (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
\r
113 switch (lvalue.XmlType.TypeCode) {
\r
114 case XmlTypeCode.Decimal:
\r
115 if (rvalue.XmlType.TypeCode == XmlTypeCode.Decimal)
\r
116 return lvalue.ValueAsDecimal != rvalue.ValueAsDecimal;
\r
117 goto case XmlTypeCode.Integer;
\r
120 case XmlTypeCode.Integer:
\r
121 case XmlTypeCode.Float:
\r
122 case XmlTypeCode.Double:
\r
123 switch (rvalue.XmlType.TypeCode) {
\r
124 case XmlTypeCode.Integer:
\r
125 case XmlTypeCode.Decimal:
\r
126 case XmlTypeCode.Float:
\r
127 case XmlTypeCode.Double:
\r
128 return lvalue.ValueAsDouble != rvalue.ValueAsDouble;
\r
132 // FIXME: handle Gregorian (gXXX) types
\r
136 if (lvalue.XmlType.TypeCode != rvalue.XmlType.TypeCode)
\r
137 return !CompareEquality (lvalue, rvalue);
\r
140 throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
\r
143 private static bool CompareLT (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
\r
145 switch (lvalue.XmlType.TypeCode) {
\r
146 case XmlTypeCode.Boolean:
\r
147 return OpBooleanLessThan (lvalue.ValueAsBoolean, rvalue.ValueAsBoolean);
\r
148 case XmlTypeCode.String:
\r
149 return lvalue.Value == rvalue.Value;
\r
150 case XmlTypeCode.Date:
\r
151 case XmlTypeCode.Time:
\r
152 case XmlTypeCode.DateTime:
\r
153 case XmlTypeCode.YearMonthDuration:
\r
154 case XmlTypeCode.DayTimeDuration:
\r
155 return lvalue.ValueAsDateTime < rvalue.ValueAsDateTime;
\r
157 throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
\r
160 public static bool ValueLT (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
\r
162 switch (lvalue.XmlType.TypeCode) {
\r
163 case XmlTypeCode.Decimal:
\r
164 if (rvalue.XmlType.TypeCode == XmlTypeCode.Decimal)
\r
165 return lvalue.ValueAsDecimal < rvalue.ValueAsDecimal;
\r
166 goto case XmlTypeCode.Integer;
\r
169 case XmlTypeCode.Integer:
\r
170 case XmlTypeCode.Float:
\r
171 case XmlTypeCode.Double:
\r
172 switch (rvalue.XmlType.TypeCode) {
\r
173 case XmlTypeCode.Integer:
\r
174 case XmlTypeCode.Decimal:
\r
175 case XmlTypeCode.Float:
\r
176 case XmlTypeCode.Double:
\r
177 return lvalue.ValueAsDouble < rvalue.ValueAsDouble;
\r
182 if (lvalue.XmlType.TypeCode != rvalue.XmlType.TypeCode)
\r
183 return CompareLT (lvalue, rvalue);
\r
186 throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
\r
189 private static bool CompareLE (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
\r
191 switch (lvalue.XmlType.TypeCode) {
\r
192 case XmlTypeCode.Boolean:
\r
193 return !OpBooleanGreaterThan (lvalue.ValueAsBoolean, rvalue.ValueAsBoolean);
\r
194 case XmlTypeCode.String:
\r
195 return lvalue.Value == rvalue.Value;
\r
196 case XmlTypeCode.Date:
\r
197 case XmlTypeCode.Time:
\r
198 case XmlTypeCode.DateTime:
\r
199 case XmlTypeCode.YearMonthDuration:
\r
200 case XmlTypeCode.DayTimeDuration:
\r
201 return lvalue.ValueAsDateTime <= rvalue.ValueAsDateTime;
\r
203 throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
\r
206 public static bool ValueLE (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
\r
208 switch (lvalue.XmlType.TypeCode) {
\r
209 case XmlTypeCode.Decimal:
\r
210 if (rvalue.XmlType.TypeCode == XmlTypeCode.Decimal)
\r
211 return lvalue.ValueAsDecimal <= rvalue.ValueAsDecimal;
\r
212 goto case XmlTypeCode.Integer;
\r
215 case XmlTypeCode.Integer:
\r
216 case XmlTypeCode.Float:
\r
217 case XmlTypeCode.Double:
\r
218 switch (rvalue.XmlType.TypeCode) {
\r
219 case XmlTypeCode.Integer:
\r
220 case XmlTypeCode.Decimal:
\r
221 case XmlTypeCode.Float:
\r
222 case XmlTypeCode.Double:
\r
223 return lvalue.ValueAsDouble <= rvalue.ValueAsDouble;
\r
228 if (lvalue.XmlType.TypeCode != rvalue.XmlType.TypeCode)
\r
229 return CompareLE (lvalue, rvalue);
\r
232 throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
\r
235 private static bool CompareGT (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
\r
237 switch (lvalue.XmlType.TypeCode) {
\r
238 case XmlTypeCode.Boolean:
\r
239 return OpBooleanGreaterThan (lvalue.ValueAsBoolean, rvalue.ValueAsBoolean);
\r
240 case XmlTypeCode.String:
\r
241 return lvalue.Value == rvalue.Value;
\r
242 case XmlTypeCode.Date:
\r
243 case XmlTypeCode.Time:
\r
244 case XmlTypeCode.DateTime:
\r
245 case XmlTypeCode.YearMonthDuration:
\r
246 case XmlTypeCode.DayTimeDuration:
\r
247 return lvalue.ValueAsDateTime > rvalue.ValueAsDateTime;
\r
249 throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
\r
252 public static bool ValueGT (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
\r
254 switch (lvalue.XmlType.TypeCode) {
\r
255 case XmlTypeCode.Decimal:
\r
256 if (rvalue.XmlType.TypeCode == XmlTypeCode.Decimal)
\r
257 return lvalue.ValueAsDecimal > rvalue.ValueAsDecimal;
\r
258 goto case XmlTypeCode.Integer;
\r
261 case XmlTypeCode.Integer:
\r
262 case XmlTypeCode.Float:
\r
263 case XmlTypeCode.Double:
\r
264 switch (rvalue.XmlType.TypeCode) {
\r
265 case XmlTypeCode.Integer:
\r
266 case XmlTypeCode.Decimal:
\r
267 case XmlTypeCode.Float:
\r
268 case XmlTypeCode.Double:
\r
269 return lvalue.ValueAsDouble > rvalue.ValueAsDouble;
\r
274 if (lvalue.XmlType.TypeCode != rvalue.XmlType.TypeCode)
\r
275 return CompareGT (lvalue, rvalue);
\r
278 throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
\r
281 private static bool CompareGE (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
\r
283 switch (lvalue.XmlType.TypeCode) {
\r
284 case XmlTypeCode.Boolean:
\r
285 return !OpBooleanLessThan (lvalue.ValueAsBoolean, rvalue.ValueAsBoolean);
\r
286 case XmlTypeCode.String:
\r
287 return lvalue.Value == rvalue.Value;
\r
288 case XmlTypeCode.Date:
\r
289 case XmlTypeCode.Time:
\r
290 case XmlTypeCode.DateTime:
\r
291 case XmlTypeCode.YearMonthDuration:
\r
292 case XmlTypeCode.DayTimeDuration:
\r
293 return lvalue.ValueAsDateTime >= rvalue.ValueAsDateTime;
\r
295 throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
\r
298 public static bool ValueGE (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
\r
300 switch (lvalue.XmlType.TypeCode) {
\r
301 case XmlTypeCode.Decimal:
\r
302 if (rvalue.XmlType.TypeCode == XmlTypeCode.Decimal)
\r
303 return lvalue.ValueAsDecimal >= rvalue.ValueAsDecimal;
\r
304 goto case XmlTypeCode.Integer;
\r
307 case XmlTypeCode.Integer:
\r
308 case XmlTypeCode.Float:
\r
309 case XmlTypeCode.Double:
\r
310 switch (rvalue.XmlType.TypeCode) {
\r
311 case XmlTypeCode.Integer:
\r
312 case XmlTypeCode.Decimal:
\r
313 case XmlTypeCode.Float:
\r
314 case XmlTypeCode.Double:
\r
315 return lvalue.ValueAsDouble >= rvalue.ValueAsDouble;
\r
320 if (lvalue.XmlType.TypeCode != rvalue.XmlType.TypeCode)
\r
321 return CompareGE (lvalue, rvalue);
\r
324 throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
\r