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