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.UntypedAtomic:
\r
62 case XmlTypeCode.String:
\r
63 return lvalue.Value == rvalue.Value;
\r
64 case XmlTypeCode.Date:
\r
65 case XmlTypeCode.Time:
\r
66 case XmlTypeCode.DateTime:
\r
67 case XmlTypeCode.YearMonthDuration:
\r
68 case XmlTypeCode.DayTimeDuration:
\r
69 return lvalue.ValueAsDateTime == rvalue.ValueAsDateTime;
\r
70 case XmlTypeCode.HexBinary:
\r
71 case XmlTypeCode.Base64Binary:
\r
72 case XmlTypeCode.AnyUri:
\r
73 case XmlTypeCode.QName:
\r
74 case XmlTypeCode.Notation:
\r
75 throw new NotImplementedException ();
\r
77 XmlQualifiedName nameL = lvalue.XmlType.QualifiedName != XmlQualifiedName.Empty ? lvalue.XmlType.QualifiedName : new XmlQualifiedName ("anyType", XmlSchema.Namespace);
\r
78 XmlQualifiedName nameR = rvalue.XmlType.QualifiedName != XmlQualifiedName.Empty ? rvalue.XmlType.QualifiedName : new XmlQualifiedName ("anyType", XmlSchema.Namespace);
\r
79 throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", nameL, nameR));
\r
82 public static bool ValueEQ (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
\r
84 if (lvalue.XmlType.TypeCode == XmlTypeCode.Decimal &&
\r
85 rvalue.XmlType.TypeCode == XmlTypeCode.Decimal)
\r
86 return lvalue.ValueAsDecimal == rvalue.ValueAsDecimal;
\r
87 if (SequenceType.IsNumeric (lvalue.XmlType.TypeCode) &&
\r
88 SequenceType.IsNumeric (lvalue.XmlType.TypeCode))
\r
89 return lvalue.ValueAsDouble == rvalue.ValueAsDouble;
\r
90 if (lvalue.XmlType.TypeCode == rvalue.XmlType.TypeCode)
\r
91 return CompareEquality (lvalue, rvalue);
\r
93 throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
\r
96 public static bool ValueNE (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
\r
98 if (lvalue.XmlType.TypeCode == XmlTypeCode.Decimal &&
\r
99 rvalue.XmlType.TypeCode == XmlTypeCode.Decimal)
\r
100 return lvalue.ValueAsDecimal != rvalue.ValueAsDecimal;
\r
101 if (SequenceType.IsNumeric (lvalue.XmlType.TypeCode) &&
\r
102 SequenceType.IsNumeric (lvalue.XmlType.TypeCode))
\r
103 return lvalue.ValueAsDouble != rvalue.ValueAsDouble;
\r
104 if (lvalue.XmlType.TypeCode == rvalue.XmlType.TypeCode)
\r
105 return !CompareEquality (lvalue, rvalue);
\r
107 throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
\r
110 private static bool CompareLT (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
\r
112 switch (lvalue.XmlType.TypeCode) {
\r
113 case XmlTypeCode.Boolean:
\r
114 return OpBooleanLessThan (lvalue.ValueAsBoolean, rvalue.ValueAsBoolean);
\r
115 case XmlTypeCode.String:
\r
116 return lvalue.Value == rvalue.Value;
\r
117 case XmlTypeCode.Date:
\r
118 case XmlTypeCode.Time:
\r
119 case XmlTypeCode.DateTime:
\r
120 case XmlTypeCode.YearMonthDuration:
\r
121 case XmlTypeCode.DayTimeDuration:
\r
122 return lvalue.ValueAsDateTime < rvalue.ValueAsDateTime;
\r
124 throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
\r
127 public static bool ValueLT (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
\r
129 if (lvalue.XmlType.TypeCode == XmlTypeCode.Decimal &&
\r
130 rvalue.XmlType.TypeCode == XmlTypeCode.Decimal)
\r
131 return lvalue.ValueAsDecimal < rvalue.ValueAsDecimal;
\r
132 if (SequenceType.IsNumeric (lvalue.XmlType.TypeCode) &&
\r
133 SequenceType.IsNumeric (lvalue.XmlType.TypeCode))
\r
134 return lvalue.ValueAsDouble < rvalue.ValueAsDouble;
\r
135 if (lvalue.XmlType.TypeCode == rvalue.XmlType.TypeCode)
\r
136 return CompareLT (lvalue, rvalue);
\r
138 throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
\r
141 private static bool CompareLE (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
\r
143 switch (lvalue.XmlType.TypeCode) {
\r
144 case XmlTypeCode.Boolean:
\r
145 return !OpBooleanGreaterThan (lvalue.ValueAsBoolean, rvalue.ValueAsBoolean);
\r
146 case XmlTypeCode.String:
\r
147 return lvalue.Value == rvalue.Value;
\r
148 case XmlTypeCode.Date:
\r
149 case XmlTypeCode.Time:
\r
150 case XmlTypeCode.DateTime:
\r
151 case XmlTypeCode.YearMonthDuration:
\r
152 case XmlTypeCode.DayTimeDuration:
\r
153 return lvalue.ValueAsDateTime <= rvalue.ValueAsDateTime;
\r
155 throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
\r
158 public static bool ValueLE (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
\r
160 if (lvalue.XmlType.TypeCode == XmlTypeCode.Decimal &&
\r
161 rvalue.XmlType.TypeCode == XmlTypeCode.Decimal)
\r
162 return lvalue.ValueAsDecimal <= rvalue.ValueAsDecimal;
\r
163 if (SequenceType.IsNumeric (lvalue.XmlType.TypeCode) &&
\r
164 SequenceType.IsNumeric (lvalue.XmlType.TypeCode))
\r
165 return lvalue.ValueAsDouble <= rvalue.ValueAsDouble;
\r
166 if (lvalue.XmlType.TypeCode == rvalue.XmlType.TypeCode)
\r
167 return CompareLE (lvalue, rvalue);
\r
169 throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
\r
172 private static bool CompareGT (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
\r
174 switch (lvalue.XmlType.TypeCode) {
\r
175 case XmlTypeCode.Boolean:
\r
176 return OpBooleanGreaterThan (lvalue.ValueAsBoolean, rvalue.ValueAsBoolean);
\r
177 case XmlTypeCode.String:
\r
178 return lvalue.Value == rvalue.Value;
\r
179 case XmlTypeCode.Date:
\r
180 case XmlTypeCode.Time:
\r
181 case XmlTypeCode.DateTime:
\r
182 case XmlTypeCode.YearMonthDuration:
\r
183 case XmlTypeCode.DayTimeDuration:
\r
184 return lvalue.ValueAsDateTime > rvalue.ValueAsDateTime;
\r
186 throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
\r
189 public static bool ValueGT (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
\r
191 if (lvalue.XmlType.TypeCode == XmlTypeCode.Decimal &&
\r
192 rvalue.XmlType.TypeCode == XmlTypeCode.Decimal)
\r
193 return lvalue.ValueAsDecimal > rvalue.ValueAsDecimal;
\r
194 if (SequenceType.IsNumeric (lvalue.XmlType.TypeCode) &&
\r
195 SequenceType.IsNumeric (lvalue.XmlType.TypeCode))
\r
196 return lvalue.ValueAsDouble > rvalue.ValueAsDouble;
\r
197 if (lvalue.XmlType.TypeCode == rvalue.XmlType.TypeCode)
\r
198 return CompareGT (lvalue, rvalue);
\r
200 throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
\r
203 private static bool CompareGE (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
\r
205 switch (lvalue.XmlType.TypeCode) {
\r
206 case XmlTypeCode.Boolean:
\r
207 return !OpBooleanLessThan (lvalue.ValueAsBoolean, rvalue.ValueAsBoolean);
\r
208 case XmlTypeCode.String:
\r
209 return lvalue.Value == rvalue.Value;
\r
210 case XmlTypeCode.Date:
\r
211 case XmlTypeCode.Time:
\r
212 case XmlTypeCode.DateTime:
\r
213 case XmlTypeCode.YearMonthDuration:
\r
214 case XmlTypeCode.DayTimeDuration:
\r
215 return lvalue.ValueAsDateTime >= rvalue.ValueAsDateTime;
\r
217 throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
\r
220 public static bool ValueGE (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
\r
222 if (lvalue.XmlType.TypeCode == XmlTypeCode.Decimal &&
\r
223 rvalue.XmlType.TypeCode == XmlTypeCode.Decimal)
\r
224 return lvalue.ValueAsDecimal >= rvalue.ValueAsDecimal;
\r
225 if (SequenceType.IsNumeric (lvalue.XmlType.TypeCode) &&
\r
226 SequenceType.IsNumeric (lvalue.XmlType.TypeCode))
\r
227 return lvalue.ValueAsDouble >= rvalue.ValueAsDouble;
\r
228 if (lvalue.XmlType.TypeCode == rvalue.XmlType.TypeCode)
\r
229 return CompareGE (lvalue, rvalue);
\r
231 throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
\r