2004-08-31 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.XML / System.Xml.Query / XQueryComparisonOperator.cs
1 //\r
2 // XQueryComparisonOperator.cs\r
3 //\r
4 // Author:\r
5 //      Atsushi Enomoto <atsushi@ximian.com>\r
6 //\r
7 //\r
8 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)\r
9 //\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
17 // \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
20 // \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
28 //\r
29 \r
30 #if NET_2_0\r
31 using System;\r
32 using System.Collections;\r
33 using System.Reflection;\r
34 using System.Xml;\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
39 \r
40 namespace Mono.Xml.XPath2\r
41 {\r
42         // FIXME: Handle complete type promotion and subtype substitution.\r
43         // See XQuery 1.0 Appendix B.*.\r
44         public class XQueryComparisonOperator\r
45         {\r
46                 private static bool OpBooleanLessThan (bool b1, bool b2)\r
47                 {\r
48                         return !b1 && b2;\r
49                 }\r
50 \r
51                 private static bool OpBooleanGreaterThan (bool b1, bool b2)\r
52                 {\r
53                         return b1 && !b2;\r
54                 }\r
55 \r
56                 private static bool CompareEquality (XPathAtomicValue lvalue, XPathAtomicValue rvalue)\r
57                 {\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
75                         }\r
76                         throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));\r
77                 }\r
78 \r
79                 public static bool ValueEQ (XPathAtomicValue lvalue, XPathAtomicValue rvalue)\r
80                 {\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
86 \r
87                         // numerics\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
97                                 }\r
98                                 break;\r
99 \r
100                         // FIXME: handle Gregorian (gXXX) types\r
101 \r
102                         // other types\r
103                         default:\r
104                                 if (lvalue.XmlType.TypeCode != rvalue.XmlType.TypeCode)\r
105                                         return CompareEquality (lvalue, rvalue);\r
106                                 break;\r
107                         }\r
108                         throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));\r
109                 }\r
110 \r
111                 public static bool ValueNE (XPathAtomicValue lvalue, XPathAtomicValue rvalue)\r
112                 {\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
118 \r
119                         // numerics\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
129                                 }\r
130                                 break;\r
131 \r
132                         // FIXME: handle Gregorian (gXXX) types\r
133 \r
134                         // other types\r
135                         default:\r
136                                 if (lvalue.XmlType.TypeCode != rvalue.XmlType.TypeCode)\r
137                                         return !CompareEquality (lvalue, rvalue);\r
138                                 break;\r
139                         }\r
140                         throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));\r
141                 }\r
142 \r
143                 private static bool CompareLT (XPathAtomicValue lvalue, XPathAtomicValue rvalue)\r
144                 {\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
156                         }\r
157                         throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));\r
158                 }\r
159 \r
160                 public static bool ValueLT (XPathAtomicValue lvalue, XPathAtomicValue rvalue)\r
161                 {\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
167 \r
168                         // numerics\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
178                                 }\r
179                                 break;\r
180 \r
181                         default:\r
182                                 if (lvalue.XmlType.TypeCode != rvalue.XmlType.TypeCode)\r
183                                         return CompareLT (lvalue, rvalue);\r
184                                 break;\r
185                         }\r
186                         throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));\r
187                 }\r
188 \r
189                 private static bool CompareLE (XPathAtomicValue lvalue, XPathAtomicValue rvalue)\r
190                 {\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
202                         }\r
203                         throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));\r
204                 }\r
205 \r
206                 public static bool ValueLE (XPathAtomicValue lvalue, XPathAtomicValue rvalue)\r
207                 {\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
213 \r
214                         // numerics\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
224                                 }\r
225                                 break;\r
226 \r
227                         default:\r
228                                 if (lvalue.XmlType.TypeCode != rvalue.XmlType.TypeCode)\r
229                                         return CompareLE (lvalue, rvalue);\r
230                                 break;\r
231                         }\r
232                         throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));\r
233                 }\r
234 \r
235                 private static bool CompareGT (XPathAtomicValue lvalue, XPathAtomicValue rvalue)\r
236                 {\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
248                         }\r
249                         throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));\r
250                 }\r
251 \r
252                 public static bool ValueGT (XPathAtomicValue lvalue, XPathAtomicValue rvalue)\r
253                 {\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
259 \r
260                         // numerics\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
270                                 }\r
271                                 break;\r
272 \r
273                         default:\r
274                                 if (lvalue.XmlType.TypeCode != rvalue.XmlType.TypeCode)\r
275                                         return CompareGT (lvalue, rvalue);\r
276                                 break;\r
277                         }\r
278                         throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));\r
279                 }\r
280 \r
281                 private static bool CompareGE (XPathAtomicValue lvalue, XPathAtomicValue rvalue)\r
282                 {\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
294                         }\r
295                         throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));\r
296                 }\r
297 \r
298                 public static bool ValueGE (XPathAtomicValue lvalue, XPathAtomicValue rvalue)\r
299                 {\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
305 \r
306                         // numerics\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
316                                 }\r
317                                 break;\r
318 \r
319                         default:\r
320                                 if (lvalue.XmlType.TypeCode != rvalue.XmlType.TypeCode)\r
321                                         return CompareGE (lvalue, rvalue);\r
322                                 break;\r
323                         }\r
324                         throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));\r
325                 }\r
326         }\r
327 }\r
328 #endif\r