2006-02-20 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.XML / System.Xml.Schema / XmlAtomicValue.cs
1 //
2 // XmlAtomicValue.cs
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // (C)2004 Novell Inc.
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 #if NET_2_0
32
33 using System.Collections;
34 using System.Xml;
35 using System.Xml.XPath;
36
37 namespace System.Xml.Schema
38 {
39         [MonoTODO ("This class is unused and thus won't be finished.")]
40         public sealed class XmlAtomicValue : XPathItem, ICloneable
41         {
42                 bool booleanValue;
43                 DateTime dateTimeValue;
44                 decimal decimalValue;
45                 double doubleValue;
46                 int intValue;
47                 long longValue;
48                 object objectValue;
49                 float floatValue;
50                 string stringValue;
51                 XmlSchemaType schemaType;
52                 XmlTypeCode xmlTypeCode;
53                 ICollection valueAsList;
54
55                 #region Constructors
56
57                 internal XmlAtomicValue (bool value, XmlSchemaType xmlType)
58                 {
59                         Init (value, xmlType);
60                 }
61                 
62                 private void Init (bool value, XmlSchemaType xmlType)
63                 {
64                         if (xmlType == null)
65                                 throw new ArgumentNullException ("xmlType");
66                         xmlTypeCode = XmlTypeCode.Boolean;
67                         this.booleanValue = value;
68                         schemaType = xmlType;
69                 }
70
71                 internal XmlAtomicValue (DateTime value, XmlSchemaType xmlType)
72                 {
73                         Init (value, xmlType);
74                 }
75                 
76                 private void Init (DateTime value, XmlSchemaType xmlType)
77                 {
78                         if (xmlType == null)
79                                 throw new ArgumentNullException ("xmlType");
80                         xmlTypeCode = XmlTypeCode.DateTime;
81                         this.dateTimeValue = value;
82                         schemaType = xmlType;
83                 }
84
85                 internal XmlAtomicValue (decimal value, XmlSchemaType xmlType)
86                 {
87                         Init (value, xmlType);
88                 }
89                 
90                 private void Init (decimal value, XmlSchemaType xmlType)
91                 {
92                         if (xmlType == null)
93                                 throw new ArgumentNullException ("xmlType");
94                         xmlTypeCode = XmlTypeCode.Decimal;
95                         this.decimalValue = value;
96                         schemaType = xmlType;
97                 }
98
99                 internal XmlAtomicValue (double value, XmlSchemaType xmlType)
100                 {
101                         Init (value, xmlType);
102                 }
103                 
104                 private void Init (double value, XmlSchemaType xmlType)
105                 {
106                         if (xmlType == null)
107                                 throw new ArgumentNullException ("xmlType");
108                         xmlTypeCode = XmlTypeCode.Double;
109                         this.doubleValue = value;
110                         schemaType = xmlType;
111                 }
112
113                 internal XmlAtomicValue (int value, XmlSchemaType xmlType)
114                 {
115                         Init (value, xmlType);
116                 }
117                 
118                 private void Init (int value, XmlSchemaType xmlType)
119                 {
120                         if (xmlType == null)
121                                 throw new ArgumentNullException ("xmlType");
122                         xmlTypeCode = XmlTypeCode.Int;
123                         this.intValue = value;
124                         schemaType = xmlType;
125                 }
126
127                 internal XmlAtomicValue (long value, XmlSchemaType xmlType)
128                 {
129                         Init (value, xmlType);
130                 }
131                 
132                 private void Init (long value, XmlSchemaType xmlType)
133                 {
134                         if (xmlType == null)
135                                 throw new ArgumentNullException ("xmlType");
136                         xmlTypeCode = XmlTypeCode.Long;
137                         this.longValue = value;
138                         schemaType = xmlType;
139                 }
140
141                 internal XmlAtomicValue (float value, XmlSchemaType xmlType)
142                 {
143                         Init (value, xmlType);
144                 }
145                 
146                 private void Init (float value, XmlSchemaType xmlType)
147                 {
148                         if (xmlType == null)
149                                 throw new ArgumentNullException ("xmlType");
150                         xmlTypeCode = XmlTypeCode.Float;
151                         this.floatValue = value;
152                         schemaType = xmlType;
153                 }
154
155                 internal XmlAtomicValue (string value, XmlSchemaType xmlType)
156                 {
157                         Init (value, xmlType);
158                 }
159                 
160                 private void Init (string value, XmlSchemaType xmlType)
161                 {
162                         if (value == null)
163                                 throw new ArgumentNullException ("value");
164                         if (xmlType == null)
165                                 throw new ArgumentNullException ("xmlType");
166                         xmlTypeCode = XmlTypeCode.String;
167                         this.stringValue = value;
168                         schemaType = xmlType;
169                 }
170
171                 internal XmlAtomicValue (object value, XmlSchemaType xmlType)
172                 {
173                         Init (value, xmlType);
174                 }
175
176                 private void Init (object value, XmlSchemaType xmlType)
177                 {
178                         // It accepts any kind of object, but will be rejected on each value properties.
179                         if (value == null)
180                                 throw new ArgumentNullException ("value");
181                         if (xmlType == null)
182                                 throw new ArgumentNullException ("xmlType");
183
184                         switch (Type.GetTypeCode (value.GetType ())) {
185                         case TypeCode.Int16:
186                         case TypeCode.UInt16:
187                         case TypeCode.Int32:
188                                 Init ((int) value, xmlType);
189                                 return;
190                         case TypeCode.Decimal:
191                                 Init ((decimal) value, xmlType);
192                                 return;
193                         case TypeCode.Double:
194                                 Init ((double) value, xmlType);
195                                 return;
196                         case TypeCode.Single:
197                                 Init ((float) value, xmlType);
198                                 return;
199                         case TypeCode.Int64:
200                         case TypeCode.UInt32:
201                                 Init ((long) value, xmlType);
202                                 return;
203                         case TypeCode.String:
204                                 Init ((string) value, xmlType);
205                                 return;
206                         case TypeCode.DateTime:
207                                 Init ((DateTime) value, xmlType);
208                                 return;
209                         case TypeCode.Boolean:
210                                 Init ((bool) value, xmlType);
211                                 return;
212                         }
213
214                         ICollection col = value as ICollection;
215                         if (col != null && col.Count == 1) {
216                                 if (col is IList)
217                                         Init (((IList) col) [0], xmlType);
218                                 else {
219                                         IEnumerator en = col.GetEnumerator ();
220                                         if (!en.MoveNext ())
221                                                 return;
222                                         if (en.Current is DictionaryEntry)
223                                                 Init (((DictionaryEntry) en.Current).Value, xmlType);
224                                         else
225                                                 Init (en.Current, xmlType);
226                                 }
227                                 return;
228                         }
229
230                         XmlAtomicValue another = value as XmlAtomicValue;
231                         if (another != null) {
232                                 switch (another.xmlTypeCode) {
233                                 case XmlTypeCode.Boolean:
234                                         Init (another.booleanValue, xmlType);
235                                         return;
236                                 case XmlTypeCode.DateTime:
237                                         Init (another.dateTimeValue, xmlType);
238                                         return;
239                                 case XmlTypeCode.Decimal:
240                                         Init (another.decimalValue, xmlType);
241                                         return;
242                                 case XmlTypeCode.Double:
243                                         Init (another.doubleValue, xmlType);
244                                         return;
245                                 case XmlTypeCode.Int:
246                                         Init (another.intValue, xmlType);
247                                         return;
248                                 case XmlTypeCode.Long:
249                                         Init (another.longValue, xmlType);
250                                         return;
251                                 case XmlTypeCode.Float:
252                                         Init (another.floatValue, xmlType);
253                                         return;
254                                 case XmlTypeCode.String:
255                                         Init (another.stringValue, xmlType);
256                                         return;
257                                 default:
258                                         objectValue = another.objectValue;
259                                         break;
260                                 }
261                         }
262
263                         objectValue = value;
264                         schemaType = xmlType;
265                 }
266
267                 #endregion
268
269                 #region Methods
270
271                 object ICloneable.Clone ()
272                 {
273                         return this.Clone ();
274                 }
275
276                 public XmlAtomicValue Clone ()
277                 {
278                         return new XmlAtomicValue (this, schemaType);
279                 }
280
281                 public override object ValueAs (Type type, IXmlNamespaceResolver nsResolver)
282                 {
283                         switch (XmlTypeCodeFromRuntimeType (type, false)) {
284                         case XmlTypeCode.Int:
285                         case XmlTypeCode.Short:
286                         case XmlTypeCode.UnsignedShort:
287                                 return ValueAsInt;
288                         case XmlTypeCode.Double:
289                         case XmlTypeCode.Float:
290                                 return ValueAsDouble;
291                         case XmlTypeCode.Long:
292                         case XmlTypeCode.UnsignedInt:
293                                 return ValueAsLong;
294                         case XmlTypeCode.String:
295                                 return Value;
296                         case XmlTypeCode.DateTime:
297                                 return ValueAsDateTime;
298                         case XmlTypeCode.Boolean:
299                                 return ValueAsBoolean;
300                         case XmlTypeCode.Item:
301                                 return TypedValue;
302                         case XmlTypeCode.QName:
303                                 return XmlQualifiedName.Parse (Value, nsResolver);
304                         }
305                         throw new NotImplementedException ();
306                 }
307
308                 #endregion
309
310                 #region Properties
311
312                 // As long as I tried, neither of such XmlAtomicValue created
313                 // with XmlText that contains atomic value, XmlElement that
314                 // contains such XmlText, XmlDocument nor XPathNavigator 
315                 // created from such nodes returned false. So it won't be 
316                 // true on this class. Apparently this class needs more
317                 // documentation.
318                 public override bool IsNode {
319                         get { return false; }
320                 }
321
322                 internal XmlTypeCode ResolvedTypeCode {
323                         get {
324                                 if (schemaType != XmlSchemaComplexType.AnyType)
325                                         return schemaType.TypeCode;
326                                 else
327                                         return xmlTypeCode;
328                         }
329                 }
330
331                 public override object TypedValue {
332                         get {
333                                 switch (ResolvedTypeCode) {
334                                 case XmlTypeCode.Boolean:
335                                         return ValueAsBoolean;
336                                 case XmlTypeCode.DateTime:
337                                         return ValueAsDateTime;
338                                 case XmlTypeCode.Float:
339                                 case XmlTypeCode.Double:
340                                         return ValueAsDouble;
341                                 case XmlTypeCode.Long:
342                                         return ValueAsLong;
343                                 case XmlTypeCode.Int:
344                                         return ValueAsInt;
345                                 case XmlTypeCode.String:
346                                         return Value;
347                                 }
348                                 return objectValue;
349                         }
350                 }
351
352                 // This method works like ValueAsString.
353                 public override string Value {
354                         get {
355                                 switch (ResolvedTypeCode) {
356                                 case XmlTypeCode.Boolean:
357                                         stringValue = XQueryConvert.BooleanToString (ValueAsBoolean);
358                                         break;
359                                 case XmlTypeCode.DateTime:
360                                         stringValue = XQueryConvert.DateTimeToString (ValueAsDateTime);
361                                         break;
362                                 case XmlTypeCode.Float:
363                                 case XmlTypeCode.Double:
364                                         stringValue = XQueryConvert.DoubleToString (ValueAsDouble);
365                                         break;
366                                 case XmlTypeCode.Long:
367                                         stringValue = XQueryConvert.IntegerToString (ValueAsLong);
368                                         break;
369                                 case XmlTypeCode.Int:
370                                         stringValue = XQueryConvert.IntToString (ValueAsInt);
371                                         break;
372                                 case XmlTypeCode.String:
373                                         return stringValue;
374
375                                 case XmlTypeCode.None:
376                                 case XmlTypeCode.Item:
377                                 case XmlTypeCode.AnyAtomicType:
378                                         switch (XmlTypeCodeFromRuntimeType (objectValue.GetType (), false)) {
379                                         case XmlTypeCode.String:
380                                                 stringValue = (string) objectValue;
381                                                 break;
382                                         case XmlTypeCode.DateTime:
383                                                 stringValue = XQueryConvert.DateTimeToString ((DateTime) objectValue);
384                                                 break;
385                                         case XmlTypeCode.Boolean:
386                                                 stringValue = XQueryConvert.BooleanToString ((bool) objectValue);
387                                                 break;
388                                         case XmlTypeCode.Float:
389                                                 stringValue = XQueryConvert.FloatToString ((float) objectValue);
390                                                 break;
391                                         case XmlTypeCode.Double:
392                                                 stringValue = XQueryConvert.DoubleToString ((double) objectValue);
393                                                 break;
394                                         case XmlTypeCode.Decimal:
395                                                 stringValue = XQueryConvert.DecimalToString ((decimal) objectValue);
396                                                 break;
397                                         case XmlTypeCode.Long:
398                                                 stringValue = XQueryConvert.IntegerToString ((long) objectValue);
399                                                 break;
400                                         case XmlTypeCode.Int:
401                                                 stringValue = XQueryConvert.IntToString ((int) objectValue);
402                                                 break;
403                                         }
404                                         break;
405                                 }
406                                 if (stringValue != null)
407                                         return stringValue;
408
409                                 if (objectValue != null)
410                                         throw new InvalidCastException (String.Format ("Conversion from runtime type {0} to {1} is not supported", objectValue.GetType (), XmlTypeCode.String));
411                                 else
412                                         throw new InvalidCastException (String.Format ("Conversion from schema type {0} (type code {1}) to {2} is not supported", schemaType.QualifiedName, xmlTypeCode, XmlTypeCode.String));
413                         }
414                 }
415
416                 public override bool ValueAsBoolean {
417                         get {
418                                 switch (xmlTypeCode) {
419                                 case XmlTypeCode.Boolean:
420                                         return booleanValue;
421                                 case XmlTypeCode.Decimal:
422                                         return XQueryConvert.DecimalToBoolean (decimalValue);
423                                 case XmlTypeCode.Double:
424                                         return XQueryConvert.DoubleToBoolean (doubleValue);
425                                 case XmlTypeCode.Long:
426                                         return XQueryConvert.IntegerToBoolean (longValue);
427                                 case XmlTypeCode.Int:
428                                         return XQueryConvert.IntToBoolean (intValue);
429                                 case XmlTypeCode.Float:
430                                         return XQueryConvert.FloatToBoolean (floatValue);
431                                 case XmlTypeCode.String:
432                                         return XQueryConvert.StringToBoolean (stringValue);
433
434                                 case XmlTypeCode.None:
435                                 case XmlTypeCode.Item:
436                                 case XmlTypeCode.AnyAtomicType:
437                                         if (objectValue is bool)
438                                                 return (bool) objectValue;
439                                         break;
440
441                                 }
442
443                                 throw new InvalidCastException (String.Format ("Conversion from {0} to {1} is not supported", schemaType.QualifiedName, XmlSchemaSimpleType.XsBoolean.QualifiedName));
444                         }
445                 }
446
447                 public override DateTime ValueAsDateTime {
448                         get {
449                                 switch (xmlTypeCode) {
450                                 case XmlTypeCode.DateTime:
451                                         return dateTimeValue;
452                                 case XmlTypeCode.String:
453                                         return XQueryConvert.StringToDateTime (stringValue);
454                                 case XmlTypeCode.None:
455                                 case XmlTypeCode.Item:
456                                 case XmlTypeCode.AnyAtomicType:
457                                         if (objectValue is DateTime)
458                                                 return (DateTime) objectValue;
459                                         break;
460
461                                 }
462
463                                 throw new InvalidCastException (String.Format ("Conversion from {0} to {1} is not supported", schemaType.QualifiedName, XmlSchemaSimpleType.XsDateTime.QualifiedName));
464                         }
465                 }
466
467                 public override double ValueAsDouble {
468                         get {
469                                 switch (xmlTypeCode) {
470                                 case XmlTypeCode.Boolean:
471                                         return XQueryConvert.BooleanToDouble (booleanValue);
472                                 case XmlTypeCode.Decimal:
473                                         return XQueryConvert.DecimalToDouble (decimalValue);
474                                 case XmlTypeCode.Double:
475                                         return doubleValue;
476                                 case XmlTypeCode.Long:
477                                         return XQueryConvert.IntegerToDouble (longValue);
478                                 case XmlTypeCode.Int:
479                                         return XQueryConvert.IntToDouble (intValue);
480                                 case XmlTypeCode.Float:
481                                         return XQueryConvert.FloatToDouble (floatValue);
482                                 case XmlTypeCode.String:
483                                         return XQueryConvert.StringToDouble (stringValue);
484                                 case XmlTypeCode.None:
485                                 case XmlTypeCode.Item:
486                                 case XmlTypeCode.AnyAtomicType:
487                                         if (objectValue is double)
488                                                 return (double) objectValue;
489                                         break;
490
491                                 }
492
493                                 throw new InvalidCastException (String.Format ("Conversion from {0} to {1} is not supported", schemaType.QualifiedName, XmlSchemaSimpleType.XsDouble.QualifiedName));
494                         }
495                 }
496
497                 public override int ValueAsInt {
498                         get {
499                                 switch (xmlTypeCode) {
500                                 case XmlTypeCode.Boolean:
501                                         return XQueryConvert.BooleanToInt (booleanValue);
502                                 case XmlTypeCode.Decimal:
503                                         return XQueryConvert.DecimalToInt (decimalValue);
504                                 case XmlTypeCode.Double:
505                                         return XQueryConvert.DoubleToInt (doubleValue);
506                                 case XmlTypeCode.Long:
507                                         return XQueryConvert.IntegerToInt (longValue);
508                                 case XmlTypeCode.Int:
509                                         return intValue;
510                                 case XmlTypeCode.Float:
511                                         return XQueryConvert.FloatToInt (floatValue);
512                                 case XmlTypeCode.String:
513                                         return XQueryConvert.StringToInt (stringValue);
514                                 case XmlTypeCode.None:
515                                 case XmlTypeCode.Item:
516                                 case XmlTypeCode.AnyAtomicType:
517                                         if (objectValue is int)
518                                                 return (int) objectValue;
519                                         break;
520
521                                 }
522
523                                 throw new InvalidCastException (String.Format ("Conversion from {0} to {1} is not supported", schemaType.QualifiedName, XmlSchemaSimpleType.XsInt.QualifiedName));
524                         }
525                 }
526
527                 public override long ValueAsLong {
528                         get {
529                                 switch (xmlTypeCode) {
530                                 case XmlTypeCode.Boolean:
531                                         return XQueryConvert.BooleanToInteger (booleanValue);
532                                 case XmlTypeCode.Decimal:
533                                         return XQueryConvert.DecimalToInteger (decimalValue);
534                                 case XmlTypeCode.Double:
535                                         return XQueryConvert.DoubleToInteger (doubleValue);
536                                 case XmlTypeCode.Long:
537                                         return longValue;
538                                 case XmlTypeCode.Int:
539                                         return XQueryConvert.IntegerToInt (intValue);
540                                 case XmlTypeCode.Float:
541                                         return XQueryConvert.FloatToInteger (floatValue);
542                                 case XmlTypeCode.String:
543                                         return XQueryConvert.StringToInteger (stringValue);
544                                 case XmlTypeCode.None:
545                                 case XmlTypeCode.Item:
546                                 case XmlTypeCode.AnyAtomicType:
547                                         if (objectValue is long)
548                                                 return (long) objectValue;
549                                         break;
550
551                                 }
552
553                                 throw new InvalidCastException (String.Format ("Conversion from {0} to {1} is not supported", schemaType.QualifiedName, XmlSchemaSimpleType.XsLong.QualifiedName));
554                         }
555                 }
556
557                 public override Type ValueType {
558                         get { return schemaType.Datatype.ValueType; }
559                 }
560
561                 public override XmlSchemaType XmlType {
562                         get { return schemaType; }
563                 }
564
565                 #endregion
566
567                 #region internal static members
568
569                 internal static Type RuntimeTypeFromXmlTypeCode (XmlTypeCode typeCode)
570                 {
571                         switch (typeCode) {
572                         case XmlTypeCode.Int:
573                                 return typeof (int);
574                         case XmlTypeCode.Decimal:
575                                 return typeof (decimal);
576                         case XmlTypeCode.Double:
577                                 return typeof (double);
578                         case XmlTypeCode.Float:
579                                 return typeof (float);
580                         case XmlTypeCode.Long:
581                                 return typeof (long);
582                         case XmlTypeCode.Short:
583                                 return typeof (short);
584                         case XmlTypeCode.UnsignedShort:
585                                 return typeof (ushort);
586                         case XmlTypeCode.UnsignedInt:
587                                 return typeof (uint);
588                         case XmlTypeCode.String:
589                                 return typeof (string);
590                         case XmlTypeCode.DateTime:
591                                 return typeof (DateTime);
592                         case XmlTypeCode.Boolean:
593                                 return typeof (bool);
594                         case XmlTypeCode.Item:
595                                 return typeof (object);
596                         }
597                         throw new NotSupportedException (String.Format ("XQuery internal error: Cannot infer Runtime Type from XmlTypeCode {0}.", typeCode));
598                 }
599
600                 internal static XmlTypeCode XmlTypeCodeFromRuntimeType (Type cliType, bool raiseError)
601                 {
602                         switch (Type.GetTypeCode (cliType)) {
603                         case TypeCode.Int32:
604                                 return XmlTypeCode.Int;
605                         case TypeCode.Decimal:
606                                 return XmlTypeCode.Decimal;
607                         case TypeCode.Double:
608                                 return XmlTypeCode.Double;
609                         case TypeCode.Single:
610                                 return XmlTypeCode.Float;
611                         case TypeCode.Int64:
612                                 return XmlTypeCode.Long;
613                         case TypeCode.Int16:
614                                 return XmlTypeCode.Short;
615                         case TypeCode.UInt16:
616                                 return XmlTypeCode.UnsignedShort;
617                         case TypeCode.UInt32:
618                                 return XmlTypeCode.UnsignedInt;
619                         case TypeCode.String:
620                                 return XmlTypeCode.String;
621                         case TypeCode.DateTime:
622                                 return XmlTypeCode.DateTime;
623                         case TypeCode.Boolean:
624                                 return XmlTypeCode.Boolean;
625                         case TypeCode.Object:
626                                 return XmlTypeCode.Item;
627                         }
628                         if (raiseError)
629                                 throw new NotSupportedException (String.Format ("XQuery internal error: Cannot infer XmlTypeCode from Runtime Type {0}", cliType));
630                         else
631                                 return XmlTypeCode.None;
632                 }
633                 #endregion
634         }
635 }
636
637 #endif