2 // XQueryComparisonOperator.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
8 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System
.Collections
;
33 using System
.Reflection
;
35 using System
.Xml
.Schema
;
36 using System
.Xml
.Query
;
37 using System
.Xml
.XPath
;
40 namespace Mono
.Xml
.XPath2
42 // FIXME: Handle complete type promotion and subtype substitution.
43 // See XQuery 1.0 Appendix B.*.
44 public class XQueryComparisonOperator
46 private static bool OpBooleanLessThan (bool b1
, bool b2
)
51 private static bool OpBooleanGreaterThan (bool b1
, bool b2
)
56 private static bool CompareEquality (XPathAtomicValue lvalue
, XPathAtomicValue rvalue
)
58 switch (lvalue
.XmlType
.TypeCode
) {
59 case XmlTypeCode
.Boolean
:
60 return lvalue
.ValueAsBoolean
== rvalue
.ValueAsBoolean
;
61 case XmlTypeCode
.String
:
62 return lvalue
.Value
== rvalue
.Value
;
63 case XmlTypeCode
.Date
:
64 case XmlTypeCode
.Time
:
65 case XmlTypeCode
.DateTime
:
66 case XmlTypeCode
.YearMonthDuration
:
67 case XmlTypeCode
.DayTimeDuration
:
68 return lvalue
.ValueAsDateTime
== rvalue
.ValueAsDateTime
;
69 case XmlTypeCode
.HexBinary
:
70 case XmlTypeCode
.Base64Binary
:
71 case XmlTypeCode
.AnyUri
:
72 case XmlTypeCode
.QName
:
73 case XmlTypeCode
.Notation
:
74 throw new NotImplementedException ();
76 throw new XmlQueryException (String
.Format ("Not allowed value comparison between {0} and {1}.", lvalue
.XmlType
.QualifiedName
, rvalue
.XmlType
.QualifiedName
));
79 public static bool ValueEQ (XPathAtomicValue lvalue
, XPathAtomicValue rvalue
)
81 if (lvalue
.XmlType
.TypeCode
== XmlTypeCode
.Decimal
&&
82 rvalue
.XmlType
.TypeCode
== XmlTypeCode
.Decimal
)
83 return lvalue
.ValueAsDecimal
== rvalue
.ValueAsDecimal
;
84 if (SequenceType
.IsNumeric (lvalue
.XmlType
.TypeCode
) &&
85 SequenceType
.IsNumeric (lvalue
.XmlType
.TypeCode
))
86 return lvalue
.ValueAsDouble
== rvalue
.ValueAsDouble
;
87 if (lvalue
.XmlType
.TypeCode
== rvalue
.XmlType
.TypeCode
)
88 return CompareEquality (lvalue
, rvalue
);
90 throw new XmlQueryException (String
.Format ("Not allowed value comparison between {0} and {1}.", lvalue
.XmlType
.QualifiedName
, rvalue
.XmlType
.QualifiedName
));
93 public static bool ValueNE (XPathAtomicValue lvalue
, XPathAtomicValue rvalue
)
95 if (lvalue
.XmlType
.TypeCode
== XmlTypeCode
.Decimal
&&
96 rvalue
.XmlType
.TypeCode
== XmlTypeCode
.Decimal
)
97 return lvalue
.ValueAsDecimal
!= rvalue
.ValueAsDecimal
;
98 if (SequenceType
.IsNumeric (lvalue
.XmlType
.TypeCode
) &&
99 SequenceType
.IsNumeric (lvalue
.XmlType
.TypeCode
))
100 return lvalue
.ValueAsDouble
!= rvalue
.ValueAsDouble
;
101 if (lvalue
.XmlType
.TypeCode
== rvalue
.XmlType
.TypeCode
)
102 return !CompareEquality (lvalue
, rvalue
);
104 throw new XmlQueryException (String
.Format ("Not allowed value comparison between {0} and {1}.", lvalue
.XmlType
.QualifiedName
, rvalue
.XmlType
.QualifiedName
));
107 private static bool CompareLT (XPathAtomicValue lvalue
, XPathAtomicValue rvalue
)
109 switch (lvalue
.XmlType
.TypeCode
) {
110 case XmlTypeCode
.Boolean
:
111 return OpBooleanLessThan (lvalue
.ValueAsBoolean
, rvalue
.ValueAsBoolean
);
112 case XmlTypeCode
.String
:
113 return lvalue
.Value
== rvalue
.Value
;
114 case XmlTypeCode
.Date
:
115 case XmlTypeCode
.Time
:
116 case XmlTypeCode
.DateTime
:
117 case XmlTypeCode
.YearMonthDuration
:
118 case XmlTypeCode
.DayTimeDuration
:
119 return lvalue
.ValueAsDateTime
< rvalue
.ValueAsDateTime
;
121 throw new XmlQueryException (String
.Format ("Not allowed value comparison between {0} and {1}.", lvalue
.XmlType
.QualifiedName
, rvalue
.XmlType
.QualifiedName
));
124 public static bool ValueLT (XPathAtomicValue lvalue
, XPathAtomicValue rvalue
)
126 if (lvalue
.XmlType
.TypeCode
== XmlTypeCode
.Decimal
&&
127 rvalue
.XmlType
.TypeCode
== XmlTypeCode
.Decimal
)
128 return lvalue
.ValueAsDecimal
< rvalue
.ValueAsDecimal
;
129 if (SequenceType
.IsNumeric (lvalue
.XmlType
.TypeCode
) &&
130 SequenceType
.IsNumeric (lvalue
.XmlType
.TypeCode
))
131 return lvalue
.ValueAsDouble
< rvalue
.ValueAsDouble
;
132 if (lvalue
.XmlType
.TypeCode
== rvalue
.XmlType
.TypeCode
)
133 return CompareLT (lvalue
, rvalue
);
135 throw new XmlQueryException (String
.Format ("Not allowed value comparison between {0} and {1}.", lvalue
.XmlType
.QualifiedName
, rvalue
.XmlType
.QualifiedName
));
138 private static bool CompareLE (XPathAtomicValue lvalue
, XPathAtomicValue rvalue
)
140 switch (lvalue
.XmlType
.TypeCode
) {
141 case XmlTypeCode
.Boolean
:
142 return !OpBooleanGreaterThan (lvalue
.ValueAsBoolean
, rvalue
.ValueAsBoolean
);
143 case XmlTypeCode
.String
:
144 return lvalue
.Value
== rvalue
.Value
;
145 case XmlTypeCode
.Date
:
146 case XmlTypeCode
.Time
:
147 case XmlTypeCode
.DateTime
:
148 case XmlTypeCode
.YearMonthDuration
:
149 case XmlTypeCode
.DayTimeDuration
:
150 return lvalue
.ValueAsDateTime
<= rvalue
.ValueAsDateTime
;
152 throw new XmlQueryException (String
.Format ("Not allowed value comparison between {0} and {1}.", lvalue
.XmlType
.QualifiedName
, rvalue
.XmlType
.QualifiedName
));
155 public static bool ValueLE (XPathAtomicValue lvalue
, XPathAtomicValue rvalue
)
157 if (lvalue
.XmlType
.TypeCode
== XmlTypeCode
.Decimal
&&
158 rvalue
.XmlType
.TypeCode
== XmlTypeCode
.Decimal
)
159 return lvalue
.ValueAsDecimal
<= rvalue
.ValueAsDecimal
;
160 if (SequenceType
.IsNumeric (lvalue
.XmlType
.TypeCode
) &&
161 SequenceType
.IsNumeric (lvalue
.XmlType
.TypeCode
))
162 return lvalue
.ValueAsDouble
<= rvalue
.ValueAsDouble
;
163 if (lvalue
.XmlType
.TypeCode
== rvalue
.XmlType
.TypeCode
)
164 return CompareLE (lvalue
, rvalue
);
166 throw new XmlQueryException (String
.Format ("Not allowed value comparison between {0} and {1}.", lvalue
.XmlType
.QualifiedName
, rvalue
.XmlType
.QualifiedName
));
169 private static bool CompareGT (XPathAtomicValue lvalue
, XPathAtomicValue rvalue
)
171 switch (lvalue
.XmlType
.TypeCode
) {
172 case XmlTypeCode
.Boolean
:
173 return OpBooleanGreaterThan (lvalue
.ValueAsBoolean
, rvalue
.ValueAsBoolean
);
174 case XmlTypeCode
.String
:
175 return lvalue
.Value
== rvalue
.Value
;
176 case XmlTypeCode
.Date
:
177 case XmlTypeCode
.Time
:
178 case XmlTypeCode
.DateTime
:
179 case XmlTypeCode
.YearMonthDuration
:
180 case XmlTypeCode
.DayTimeDuration
:
181 return lvalue
.ValueAsDateTime
> rvalue
.ValueAsDateTime
;
183 throw new XmlQueryException (String
.Format ("Not allowed value comparison between {0} and {1}.", lvalue
.XmlType
.QualifiedName
, rvalue
.XmlType
.QualifiedName
));
186 public static bool ValueGT (XPathAtomicValue lvalue
, XPathAtomicValue rvalue
)
188 if (lvalue
.XmlType
.TypeCode
== XmlTypeCode
.Decimal
&&
189 rvalue
.XmlType
.TypeCode
== XmlTypeCode
.Decimal
)
190 return lvalue
.ValueAsDecimal
> rvalue
.ValueAsDecimal
;
191 if (SequenceType
.IsNumeric (lvalue
.XmlType
.TypeCode
) &&
192 SequenceType
.IsNumeric (lvalue
.XmlType
.TypeCode
))
193 return lvalue
.ValueAsDouble
> rvalue
.ValueAsDouble
;
194 if (lvalue
.XmlType
.TypeCode
== rvalue
.XmlType
.TypeCode
)
195 return CompareGT (lvalue
, rvalue
);
197 throw new XmlQueryException (String
.Format ("Not allowed value comparison between {0} and {1}.", lvalue
.XmlType
.QualifiedName
, rvalue
.XmlType
.QualifiedName
));
200 private static bool CompareGE (XPathAtomicValue lvalue
, XPathAtomicValue rvalue
)
202 switch (lvalue
.XmlType
.TypeCode
) {
203 case XmlTypeCode
.Boolean
:
204 return !OpBooleanLessThan (lvalue
.ValueAsBoolean
, rvalue
.ValueAsBoolean
);
205 case XmlTypeCode
.String
:
206 return lvalue
.Value
== rvalue
.Value
;
207 case XmlTypeCode
.Date
:
208 case XmlTypeCode
.Time
:
209 case XmlTypeCode
.DateTime
:
210 case XmlTypeCode
.YearMonthDuration
:
211 case XmlTypeCode
.DayTimeDuration
:
212 return lvalue
.ValueAsDateTime
>= rvalue
.ValueAsDateTime
;
214 throw new XmlQueryException (String
.Format ("Not allowed value comparison between {0} and {1}.", lvalue
.XmlType
.QualifiedName
, rvalue
.XmlType
.QualifiedName
));
217 public static bool ValueGE (XPathAtomicValue lvalue
, XPathAtomicValue rvalue
)
219 if (lvalue
.XmlType
.TypeCode
== XmlTypeCode
.Decimal
&&
220 rvalue
.XmlType
.TypeCode
== XmlTypeCode
.Decimal
)
221 return lvalue
.ValueAsDecimal
>= rvalue
.ValueAsDecimal
;
222 if (SequenceType
.IsNumeric (lvalue
.XmlType
.TypeCode
) &&
223 SequenceType
.IsNumeric (lvalue
.XmlType
.TypeCode
))
224 return lvalue
.ValueAsDouble
>= rvalue
.ValueAsDouble
;
225 if (lvalue
.XmlType
.TypeCode
== rvalue
.XmlType
.TypeCode
)
226 return CompareGE (lvalue
, rvalue
);
228 throw new XmlQueryException (String
.Format ("Not allowed value comparison between {0} and {1}.", lvalue
.XmlType
.QualifiedName
, rvalue
.XmlType
.QualifiedName
));