5 // Atsushi Enomoto <atsushi@ximian.com>
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:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
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.
33 using System.Collections;
35 using System.Xml.XPath;
37 namespace System.Xml.Schema
39 [MonoTODO] // This class is unused and thus won't be finished.
40 public sealed class XmlAtomicValue : XPathItem, ICloneable
43 DateTime dateTimeValue;
53 XmlSchemaType schemaType;
54 XmlTypeCode xmlTypeCode;
55 //ICollection valueAsList;
59 internal XmlAtomicValue (bool value, XmlSchemaType xmlType)
61 Init (value, xmlType);
64 private void Init (bool value, XmlSchemaType xmlType)
67 throw new ArgumentNullException ("xmlType");
68 xmlTypeCode = XmlTypeCode.Boolean;
69 this.booleanValue = value;
73 internal XmlAtomicValue (byte [] value, XmlSchemaType xmlType)
75 Init (value, xmlType);
78 private void Init (byte [] value, XmlSchemaType xmlType)
81 throw new ArgumentNullException ("xmlType");
82 xmlTypeCode = XmlTypeCode.Base64Binary;
83 this.bytesValue = value;
87 internal XmlAtomicValue (DateTime value, XmlSchemaType xmlType)
89 Init (value, xmlType);
92 private void Init (DateTime value, XmlSchemaType xmlType)
95 throw new ArgumentNullException ("xmlType");
96 xmlTypeCode = XmlTypeCode.DateTime;
97 this.dateTimeValue = value;
101 internal XmlAtomicValue (decimal value, XmlSchemaType xmlType)
103 Init (value, xmlType);
106 private void Init (decimal value, XmlSchemaType xmlType)
109 throw new ArgumentNullException ("xmlType");
110 xmlTypeCode = XmlTypeCode.Decimal;
111 this.decimalValue = value;
112 schemaType = xmlType;
115 internal XmlAtomicValue (double value, XmlSchemaType xmlType)
117 Init (value, xmlType);
120 private void Init (double value, XmlSchemaType xmlType)
123 throw new ArgumentNullException ("xmlType");
124 xmlTypeCode = XmlTypeCode.Double;
125 this.doubleValue = value;
126 schemaType = xmlType;
129 internal XmlAtomicValue (int value, XmlSchemaType xmlType)
131 Init (value, xmlType);
134 private void Init (int value, XmlSchemaType xmlType)
137 throw new ArgumentNullException ("xmlType");
138 xmlTypeCode = XmlTypeCode.Int;
139 this.intValue = value;
140 schemaType = xmlType;
143 internal XmlAtomicValue (long value, XmlSchemaType xmlType)
145 Init (value, xmlType);
148 private void Init (long value, XmlSchemaType xmlType)
151 throw new ArgumentNullException ("xmlType");
152 xmlTypeCode = XmlTypeCode.Long;
153 this.longValue = value;
154 schemaType = xmlType;
157 internal XmlAtomicValue (ulong value, XmlSchemaType xmlType)
159 Init (value, xmlType);
162 private void Init (ulong value, XmlSchemaType xmlType)
165 throw new ArgumentNullException ("xmlType");
166 xmlTypeCode = XmlTypeCode.UnsignedLong;
167 this.ulongValue = value;
168 schemaType = xmlType;
171 internal XmlAtomicValue (float value, XmlSchemaType xmlType)
173 Init (value, xmlType);
176 private void Init (float value, XmlSchemaType xmlType)
179 throw new ArgumentNullException ("xmlType");
180 xmlTypeCode = XmlTypeCode.Float;
181 this.floatValue = value;
182 schemaType = xmlType;
185 internal XmlAtomicValue (string value, XmlSchemaType xmlType)
187 Init (value, xmlType);
190 private void Init (string value, XmlSchemaType xmlType)
193 throw new ArgumentNullException ("value");
195 throw new ArgumentNullException ("xmlType");
196 xmlTypeCode = XmlTypeCode.String;
197 this.stringValue = value;
198 schemaType = xmlType;
201 internal XmlAtomicValue (object value, XmlSchemaType xmlType)
203 Init (value, xmlType);
206 private void Init (object value, XmlSchemaType xmlType)
208 // It accepts any kind of object, but will be rejected on each value properties.
210 throw new ArgumentNullException ("value");
212 throw new ArgumentNullException ("xmlType");
214 switch (Type.GetTypeCode (value.GetType ())) {
216 Init ((byte) value, xmlType);
219 Init ((sbyte) value, xmlType);
222 Init ((short) value, xmlType);
224 case TypeCode.UInt16:
225 Init ((ushort) value, xmlType);
228 Init ((int) value, xmlType);
230 case TypeCode.Decimal:
231 Init ((decimal) value, xmlType);
233 case TypeCode.Double:
234 Init ((double) value, xmlType);
236 case TypeCode.Single:
237 Init ((float) value, xmlType);
240 Init ((long) value, xmlType);
242 case TypeCode.UInt32:
243 Init ((uint) value, xmlType);
245 case TypeCode.UInt64:
246 Init ((ulong) value, xmlType);
248 case TypeCode.String:
249 Init ((string) value, xmlType);
251 case TypeCode.DateTime:
252 Init ((DateTime) value, xmlType);
254 case TypeCode.Boolean:
255 Init ((bool) value, xmlType);
258 if (value is byte []) {
259 Init ((byte []) value, xmlType);
263 ICollection col = value as ICollection;
264 if (col != null && col.Count == 1) {
266 Init (((IList) col) [0], xmlType);
268 IEnumerator en = col.GetEnumerator ();
271 if (en.Current is DictionaryEntry)
272 Init (((DictionaryEntry) en.Current).Value, xmlType);
274 Init (en.Current, xmlType);
279 XmlAtomicValue another = value as XmlAtomicValue;
280 if (another != null) {
281 switch (another.xmlTypeCode) {
282 case XmlTypeCode.Boolean:
283 Init (another.booleanValue, xmlType);
285 case XmlTypeCode.DateTime:
286 Init (another.dateTimeValue, xmlType);
288 case XmlTypeCode.Decimal:
289 Init (another.decimalValue, xmlType);
291 case XmlTypeCode.Double:
292 Init (another.doubleValue, xmlType);
294 case XmlTypeCode.Int:
295 Init (another.intValue, xmlType);
297 case XmlTypeCode.Long:
298 Init (another.longValue, xmlType);
300 case XmlTypeCode.UnsignedLong:
301 Init (another.ulongValue, xmlType);
303 case XmlTypeCode.Float:
304 Init (another.floatValue, xmlType);
306 case XmlTypeCode.String:
307 Init (another.stringValue, xmlType);
310 objectValue = another.objectValue;
316 schemaType = xmlType;
323 object ICloneable.Clone ()
325 return this.Clone ();
328 public XmlAtomicValue Clone ()
330 return new XmlAtomicValue (this, schemaType);
333 public override object ValueAs (Type type, IXmlNamespaceResolver nsResolver)
335 switch (XmlTypeCodeFromRuntimeType (type, false)) {
336 case XmlTypeCode.Int:
337 case XmlTypeCode.Short:
338 case XmlTypeCode.UnsignedShort:
340 case XmlTypeCode.Decimal:
341 return ValueAsDecimal;
342 case XmlTypeCode.Double:
343 case XmlTypeCode.Float:
344 return ValueAsDouble;
345 case XmlTypeCode.Long:
346 case XmlTypeCode.UnsignedInt:
348 case XmlTypeCode.String:
350 case XmlTypeCode.DateTime:
351 return ValueAsDateTime;
352 case XmlTypeCode.Boolean:
353 return ValueAsBoolean;
354 case XmlTypeCode.Item:
356 case XmlTypeCode.QName:
357 return XmlQualifiedName.Parse (Value, nsResolver, true);
358 case XmlTypeCode.Base64Binary:
359 case XmlTypeCode.HexBinary:
360 if (bytesValue != null)
364 throw new NotImplementedException ();
367 public override string ToString ()
376 // As long as I tried, neither of such XmlAtomicValue created
377 // with XmlText that contains atomic value, XmlElement that
378 // contains such XmlText, XmlDocument nor XPathNavigator
379 // created from such nodes returned false. So it won't be
380 // true on this class. Apparently this class needs more
382 public override bool IsNode {
383 get { return false; }
386 internal XmlTypeCode ResolvedTypeCode {
388 if (schemaType != XmlSchemaComplexType.AnyType)
389 return schemaType.TypeCode;
395 public override object TypedValue {
397 switch (ResolvedTypeCode) {
398 case XmlTypeCode.Boolean:
399 return ValueAsBoolean;
400 case XmlTypeCode.DateTime:
401 return ValueAsDateTime;
402 case XmlTypeCode.Decimal:
403 return ValueAsDecimal;
404 case XmlTypeCode.Float:
405 case XmlTypeCode.Double:
406 return ValueAsDouble;
407 case XmlTypeCode.Long:
409 case XmlTypeCode.Int:
411 case XmlTypeCode.String:
418 // This method works like ValueAsString.
419 public override string Value {
421 switch (ResolvedTypeCode) {
422 case XmlTypeCode.Boolean:
423 stringValue = XQueryConvert.BooleanToString (ValueAsBoolean);
425 case XmlTypeCode.Date:
426 case XmlTypeCode.Time:
427 case XmlTypeCode.DateTime:
428 stringValue = XQueryConvert.DateTimeToString (ValueAsDateTime);
430 case XmlTypeCode.Duration:
431 stringValue = XQueryConvert.DayTimeDurationToString (TimeSpan.FromMilliseconds (doubleValue));
433 case XmlTypeCode.GYear:
434 stringValue = XQueryConvert.GYearToString (ValueAsDateTime);
436 case XmlTypeCode.GYearMonth:
437 stringValue = XQueryConvert.GYearMonthToString (ValueAsDateTime);
439 case XmlTypeCode.GMonth:
440 stringValue = XQueryConvert.GMonthToString (ValueAsDateTime);
442 case XmlTypeCode.GMonthDay:
443 stringValue = XQueryConvert.GMonthDayToString (ValueAsDateTime);
445 case XmlTypeCode.GDay:
446 stringValue = XQueryConvert.GDayToString (ValueAsDateTime);
448 case XmlTypeCode.Float:
449 case XmlTypeCode.Double:
450 stringValue = XQueryConvert.DoubleToString (ValueAsDouble);
452 case XmlTypeCode.Integer:
453 case XmlTypeCode.UnsignedInt:
454 case XmlTypeCode.UnsignedLong:
455 case XmlTypeCode.Decimal:
456 stringValue = XQueryConvert.DecimalToString (ValueAsDecimal);
458 case XmlTypeCode.NonPositiveInteger:
459 case XmlTypeCode.NonNegativeInteger:
460 case XmlTypeCode.NegativeInteger:
461 case XmlTypeCode.Long:
462 case XmlTypeCode.PositiveInteger:
463 stringValue = XQueryConvert.IntegerToString (ValueAsLong);
465 case XmlTypeCode.Int:
466 case XmlTypeCode.Short:
467 case XmlTypeCode.Byte:
468 case XmlTypeCode.UnsignedShort:
469 case XmlTypeCode.UnsignedByte:
470 stringValue = XQueryConvert.IntToString (ValueAsInt);
472 case XmlTypeCode.Base64Binary:
473 stringValue = XQueryConvert.Base64BinaryToString (bytesValue);
475 case XmlTypeCode.HexBinary:
476 stringValue = XQueryConvert.HexBinaryToString (bytesValue);
478 case XmlTypeCode.QName:
479 case XmlTypeCode.AnyUri:
480 case XmlTypeCode.String:
483 case XmlTypeCode.None:
484 case XmlTypeCode.Item:
485 case XmlTypeCode.AnyAtomicType:
486 switch (XmlTypeCodeFromRuntimeType (objectValue.GetType (), false)) {
487 case XmlTypeCode.String:
488 stringValue = (string) objectValue;
490 case XmlTypeCode.Date:
491 stringValue = XQueryConvert.DateToString ((DateTime) objectValue);
493 case XmlTypeCode.Time:
494 stringValue = XQueryConvert.TimeToString ((DateTime) objectValue);
496 case XmlTypeCode.DateTime:
497 stringValue = XQueryConvert.DateTimeToString ((DateTime) objectValue);
499 case XmlTypeCode.Duration:
500 stringValue = XQueryConvert.DayTimeDurationToString (TimeSpan.FromMilliseconds ((double) objectValue));
502 case XmlTypeCode.Boolean:
503 stringValue = XQueryConvert.BooleanToString ((bool) objectValue);
505 case XmlTypeCode.Float:
506 stringValue = XQueryConvert.FloatToString ((float) objectValue);
508 case XmlTypeCode.Double:
509 stringValue = XQueryConvert.DoubleToString ((double) objectValue);
511 case XmlTypeCode.Integer:
512 case XmlTypeCode.Decimal:
513 stringValue = XQueryConvert.DecimalToString ((decimal) objectValue);
515 case XmlTypeCode.Long:
516 stringValue = XQueryConvert.IntegerToString ((long) objectValue);
518 case XmlTypeCode.Int:
519 stringValue = XQueryConvert.IntToString ((int) objectValue);
521 case XmlTypeCode.Base64Binary:
522 stringValue = XQueryConvert.Base64BinaryToString ((byte []) objectValue);
524 case XmlTypeCode.HexBinary:
525 stringValue = XQueryConvert.HexBinaryToString ((byte []) objectValue);
530 if (stringValue != null)
533 if (objectValue != null)
534 throw new InvalidCastException (String.Format ("Conversion from runtime type {0}, resolved as type code {1}, to {2} is not supported", objectValue.GetType (), ResolvedTypeCode, XmlTypeCode.String));
536 throw new InvalidCastException (String.Format ("Conversion from schema type {0} (type code {1}, resolved type code {2}) to {3} is not supported.", schemaType.QualifiedName, xmlTypeCode, ResolvedTypeCode, XmlTypeCode.String));
540 public override bool ValueAsBoolean {
542 switch (xmlTypeCode) {
543 case XmlTypeCode.Boolean:
545 case XmlTypeCode.Decimal:
546 return XQueryConvert.DecimalToBoolean (decimalValue);
547 case XmlTypeCode.Double:
548 return XQueryConvert.DoubleToBoolean (doubleValue);
549 case XmlTypeCode.Long:
550 return XQueryConvert.IntegerToBoolean (longValue);
551 case XmlTypeCode.Int:
552 return XQueryConvert.IntToBoolean (intValue);
553 case XmlTypeCode.Float:
554 return XQueryConvert.FloatToBoolean (floatValue);
555 case XmlTypeCode.String:
556 return XQueryConvert.StringToBoolean (stringValue);
558 case XmlTypeCode.None:
559 case XmlTypeCode.Item:
560 case XmlTypeCode.AnyAtomicType:
561 if (objectValue is bool)
562 return (bool) objectValue;
567 throw new InvalidCastException (String.Format ("Conversion from {0} to {1} is not supported", schemaType.QualifiedName, XmlSchemaSimpleType.XsBoolean.QualifiedName));
571 public override DateTime ValueAsDateTime {
573 switch (xmlTypeCode) {
574 case XmlTypeCode.DateTime:
575 return dateTimeValue;
576 case XmlTypeCode.String:
577 return XQueryConvert.StringToDateTime (stringValue);
578 case XmlTypeCode.GYear:
579 return XQueryConvert.StringToGYear (stringValue);
580 case XmlTypeCode.GYearMonth:
581 return XQueryConvert.StringToGYearMonth (stringValue);
582 case XmlTypeCode.GMonth:
583 return XQueryConvert.StringToGMonth (stringValue);
584 case XmlTypeCode.GMonthDay:
585 return XQueryConvert.StringToGMonthDay (stringValue);
586 case XmlTypeCode.GDay:
587 return XQueryConvert.StringToGDay (stringValue);
588 case XmlTypeCode.None:
589 case XmlTypeCode.Item:
590 case XmlTypeCode.AnyAtomicType:
591 if (objectValue is DateTime)
592 return (DateTime) objectValue;
597 throw new InvalidCastException (String.Format ("Conversion from {0} to {1} is not supported", schemaType.QualifiedName, XmlSchemaSimpleType.XsDateTime.QualifiedName));
601 // Unlike the other ValueAs...() functions, this is not part
602 // of the XPathItem abstract class, so it's not an override
603 public decimal ValueAsDecimal {
605 switch (xmlTypeCode) {
606 case XmlTypeCode.Boolean:
607 return XQueryConvert.BooleanToDecimal (booleanValue);
608 case XmlTypeCode.Decimal:
610 case XmlTypeCode.Double:
611 return XQueryConvert.DoubleToDecimal (doubleValue);
612 case XmlTypeCode.Long:
613 return XQueryConvert.IntegerToDecimal (longValue);
614 case XmlTypeCode.UnsignedLong:
615 return XQueryConvert.IntegerToDecimal (ulongValue);
616 case XmlTypeCode.Int:
617 return XQueryConvert.IntToDecimal (intValue);
618 case XmlTypeCode.Float:
619 return XQueryConvert.FloatToDecimal (floatValue);
620 case XmlTypeCode.String:
621 return XQueryConvert.StringToDecimal (stringValue);
622 case XmlTypeCode.None:
623 case XmlTypeCode.Item:
624 case XmlTypeCode.AnyAtomicType:
625 if (objectValue is decimal)
626 return (decimal) objectValue;
630 throw new InvalidCastException (String.Format ("Conversion from {0} to {1} is not supported", schemaType.QualifiedName, XmlSchemaSimpleType.XsDecimal.QualifiedName));
634 public override double ValueAsDouble {
636 switch (xmlTypeCode) {
637 case XmlTypeCode.Boolean:
638 return XQueryConvert.BooleanToDouble (booleanValue);
639 case XmlTypeCode.Decimal:
640 return XQueryConvert.DecimalToDouble (decimalValue);
641 case XmlTypeCode.Double:
643 case XmlTypeCode.Long:
644 return XQueryConvert.IntegerToDouble (longValue);
645 case XmlTypeCode.Int:
646 return XQueryConvert.IntToDouble (intValue);
647 case XmlTypeCode.Float:
648 return XQueryConvert.FloatToDouble (floatValue);
649 case XmlTypeCode.String:
650 return XQueryConvert.StringToDouble (stringValue);
651 case XmlTypeCode.None:
652 case XmlTypeCode.Item:
653 case XmlTypeCode.AnyAtomicType:
654 if (objectValue is double)
655 return (double) objectValue;
660 throw new InvalidCastException (String.Format ("Conversion from {0} to {1} is not supported", schemaType.QualifiedName, XmlSchemaSimpleType.XsDouble.QualifiedName));
664 public override int ValueAsInt {
666 switch (xmlTypeCode) {
667 case XmlTypeCode.Boolean:
668 return XQueryConvert.BooleanToInt (booleanValue);
669 case XmlTypeCode.Decimal:
670 return XQueryConvert.DecimalToInt (decimalValue);
671 case XmlTypeCode.Double:
672 return XQueryConvert.DoubleToInt (doubleValue);
673 case XmlTypeCode.Long:
674 return XQueryConvert.IntegerToInt (longValue);
675 case XmlTypeCode.Int:
677 case XmlTypeCode.Float:
678 return XQueryConvert.FloatToInt (floatValue);
679 case XmlTypeCode.String:
680 return XQueryConvert.StringToInt (stringValue);
681 case XmlTypeCode.None:
682 case XmlTypeCode.Item:
683 case XmlTypeCode.AnyAtomicType:
684 if (objectValue is int)
685 return (int) objectValue;
690 throw new InvalidCastException (String.Format ("Conversion from {0} to {1} is not supported", schemaType.QualifiedName, XmlSchemaSimpleType.XsInt.QualifiedName));
694 public override long ValueAsLong {
696 switch (xmlTypeCode) {
697 case XmlTypeCode.Boolean:
698 return XQueryConvert.BooleanToInteger (booleanValue);
699 case XmlTypeCode.Decimal:
700 return XQueryConvert.DecimalToInteger (decimalValue);
701 case XmlTypeCode.Double:
702 return XQueryConvert.DoubleToInteger (doubleValue);
703 case XmlTypeCode.Long:
705 case XmlTypeCode.Int:
706 return XQueryConvert.IntegerToInt (intValue);
707 case XmlTypeCode.Float:
708 return XQueryConvert.FloatToInteger (floatValue);
709 case XmlTypeCode.String:
710 return XQueryConvert.StringToInteger (stringValue);
711 case XmlTypeCode.None:
712 case XmlTypeCode.Item:
713 case XmlTypeCode.AnyAtomicType:
714 if (objectValue is long)
715 return (long) objectValue;
720 throw new InvalidCastException (String.Format ("Conversion from {0} to {1} is not supported", schemaType.QualifiedName, XmlSchemaSimpleType.XsLong.QualifiedName));
724 public override Type ValueType {
725 get { return schemaType.Datatype.ValueType; }
728 public override XmlSchemaType XmlType {
729 get { return schemaType; }
734 #region internal static members
736 internal static Type RuntimeTypeFromXmlTypeCode (XmlTypeCode typeCode)
739 case XmlTypeCode.Int:
741 case XmlTypeCode.Decimal:
742 return typeof (decimal);
743 case XmlTypeCode.Double:
744 return typeof (double);
745 case XmlTypeCode.Float:
746 return typeof (float);
747 case XmlTypeCode.Long:
748 return typeof (long);
749 case XmlTypeCode.Short:
750 return typeof (short);
751 case XmlTypeCode.UnsignedShort:
752 return typeof (ushort);
753 case XmlTypeCode.UnsignedInt:
754 return typeof (uint);
755 case XmlTypeCode.String:
756 return typeof (string);
757 case XmlTypeCode.DateTime:
758 return typeof (DateTime);
759 case XmlTypeCode.Boolean:
760 return typeof (bool);
761 case XmlTypeCode.Base64Binary:
762 case XmlTypeCode.HexBinary:
763 return typeof (byte []);
764 case XmlTypeCode.Item:
765 return typeof (object);
767 throw new NotSupportedException (String.Format ("XQuery internal error: Cannot infer Runtime Type from XmlTypeCode {0}.", typeCode));
770 internal static XmlTypeCode XmlTypeCodeFromRuntimeType (Type cliType, bool raiseError)
772 switch (Type.GetTypeCode (cliType)) {
774 return XmlTypeCode.Int;
775 case TypeCode.Decimal:
776 return XmlTypeCode.Decimal;
777 case TypeCode.Double:
778 return XmlTypeCode.Double;
779 case TypeCode.Single:
780 return XmlTypeCode.Float;
782 return XmlTypeCode.Long;
784 return XmlTypeCode.Short;
785 case TypeCode.UInt16:
786 return XmlTypeCode.UnsignedShort;
787 case TypeCode.UInt32:
788 return XmlTypeCode.UnsignedInt;
789 case TypeCode.String:
790 return XmlTypeCode.String;
791 case TypeCode.DateTime:
792 return XmlTypeCode.DateTime;
793 case TypeCode.Boolean:
794 return XmlTypeCode.Boolean;
795 case TypeCode.Object:
796 if (cliType == typeof (byte []))
797 return XmlTypeCode.Base64Binary;
799 return XmlTypeCode.Item;
802 throw new NotSupportedException (String.Format ("XQuery internal error: Cannot infer XmlTypeCode from Runtime Type {0}", cliType));
804 return XmlTypeCode.None;