1 //------------------------------------------------------------------------------
2 // <copyright file="XmlAtomicValue.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">[....]</owner>
6 //------------------------------------------------------------------------------
8 using System.Collections;
9 using System.Collections.Generic;
10 using System.Runtime.InteropServices;
11 using System.Xml.XPath;
12 using System.Diagnostics;
14 namespace System.Xml.Schema {
17 /// This class contains a (CLR Object, XmlType) pair that represents an instance of an Xml atomic value.
18 /// It is optimized to avoid boxing.
20 public sealed class XmlAtomicValue : XPathItem, ICloneable {
21 private XmlSchemaType xmlType;
22 private object objVal;
23 private TypeCode clrType;
24 private Union unionVal;
25 private NamespacePrefixForQName nsPrefix;
27 [StructLayout(LayoutKind.Explicit, Size=8)]
28 private struct Union {
29 [FieldOffset(0)] public bool boolVal;
30 [FieldOffset(0)] public double dblVal;
31 [FieldOffset(0)] public long i64Val;
32 [FieldOffset(0)] public int i32Val;
33 [FieldOffset(0)] public DateTime dtVal;
36 class NamespacePrefixForQName : IXmlNamespaceResolver {
40 public NamespacePrefixForQName(string prefix, string ns) {
44 public string LookupNamespace(string prefix) {
45 if (prefix == this.prefix) {
51 public string LookupPrefix(string namespaceName) {
52 if (ns == namespaceName) {
58 public IDictionary<string, string> GetNamespacesInScope(XmlNamespaceScope scope) {
59 Dictionary<string, string> dict = new Dictionary<string, string>(1);
65 //-----------------------------------------------
66 // XmlAtomicValue constructors and methods
67 //-----------------------------------------------
69 internal XmlAtomicValue(XmlSchemaType xmlType, bool value) {
70 if (xmlType == null) throw new ArgumentNullException ("xmlType");
71 this.xmlType = xmlType;
72 this.clrType = TypeCode.Boolean;
73 this.unionVal.boolVal = value;
76 internal XmlAtomicValue(XmlSchemaType xmlType, DateTime value) {
77 if (xmlType == null) throw new ArgumentNullException ("xmlType");
78 this.xmlType = xmlType;
79 this.clrType = TypeCode.DateTime;
80 this.unionVal.dtVal = value;
83 internal XmlAtomicValue(XmlSchemaType xmlType, double value) {
84 if (xmlType == null) throw new ArgumentNullException ("xmlType");
85 this.xmlType = xmlType;
86 this.clrType = TypeCode.Double;
87 this.unionVal.dblVal = value;
90 internal XmlAtomicValue(XmlSchemaType xmlType, int value) {
91 if (xmlType == null) throw new ArgumentNullException ("xmlType");
92 this.xmlType = xmlType;
93 this.clrType = TypeCode.Int32;
94 this.unionVal.i32Val = value;
97 internal XmlAtomicValue(XmlSchemaType xmlType, long value) {
98 if (xmlType == null) throw new ArgumentNullException ("xmlType");
99 this.xmlType = xmlType;
100 this.clrType = TypeCode.Int64;
101 this.unionVal.i64Val = value;
104 internal XmlAtomicValue(XmlSchemaType xmlType, string value) {
105 if (value == null) throw new ArgumentNullException ("value");
106 if (xmlType == null) throw new ArgumentNullException ("xmlType");
107 this.xmlType = xmlType;
111 internal XmlAtomicValue(XmlSchemaType xmlType, string value, IXmlNamespaceResolver nsResolver) {
112 if (value == null) throw new ArgumentNullException ("value");
113 if (xmlType == null) throw new ArgumentNullException ("xmlType");
114 this.xmlType = xmlType;
116 if (nsResolver != null && (this.xmlType.TypeCode == XmlTypeCode.QName || this.xmlType.TypeCode == XmlTypeCode.Notation) ) {
117 string prefix = GetPrefixFromQName(value);
118 this.nsPrefix = new NamespacePrefixForQName(prefix, nsResolver.LookupNamespace(prefix));
122 internal XmlAtomicValue(XmlSchemaType xmlType, object value) {
123 if (value == null) throw new ArgumentNullException ("value");
124 if (xmlType == null) throw new ArgumentNullException ("xmlType");
125 this.xmlType = xmlType;
129 internal XmlAtomicValue(XmlSchemaType xmlType, object value, IXmlNamespaceResolver nsResolver) {
130 if (value == null) throw new ArgumentNullException("value");
131 if (xmlType == null) throw new ArgumentNullException("xmlType");
132 this.xmlType = xmlType;
135 if (nsResolver != null && (this.xmlType.TypeCode == XmlTypeCode.QName || this.xmlType.TypeCode == XmlTypeCode.Notation) ) { //Its a qualifiedName
136 XmlQualifiedName qname = this.objVal as XmlQualifiedName;
137 Debug.Assert(qname != null); //string representation is handled in a different overload
138 string ns = qname.Namespace;
139 this.nsPrefix = new NamespacePrefixForQName(nsResolver.LookupPrefix(ns), ns);
144 /// Since XmlAtomicValue is immutable, clone simply returns this.
146 public XmlAtomicValue Clone() {
151 //-----------------------------------------------
152 // ICloneable methods
153 //-----------------------------------------------
156 /// Since XmlAtomicValue is immutable, clone simply returns this.
158 object ICloneable.Clone() {
163 //-----------------------------------------------
165 //-----------------------------------------------
167 public override bool IsNode {
168 get { return false; }
171 public override XmlSchemaType XmlType {
172 get { return this.xmlType; }
175 public override Type ValueType {
176 get { return this.xmlType.Datatype.ValueType; }
179 public override object TypedValue {
181 XmlValueConverter valueConverter = this.xmlType.ValueConverter;
183 if (this.objVal == null) {
184 switch (this.clrType) {
185 case TypeCode.Boolean: return valueConverter.ChangeType(this.unionVal.boolVal, ValueType);
186 case TypeCode.Int32: return valueConverter.ChangeType(this.unionVal.i32Val, ValueType);
187 case TypeCode.Int64: return valueConverter.ChangeType(this.unionVal.i64Val, ValueType);
188 case TypeCode.Double: return valueConverter.ChangeType(this.unionVal.dblVal, ValueType);
189 case TypeCode.DateTime: return valueConverter.ChangeType(this.unionVal.dtVal, ValueType);
190 default: Debug.Assert(false, "Should never get here"); break;
193 return valueConverter.ChangeType(this.objVal, ValueType, this.nsPrefix);
197 public override bool ValueAsBoolean {
199 XmlValueConverter valueConverter = this.xmlType.ValueConverter;
201 if (this.objVal == null) {
202 switch (this.clrType) {
203 case TypeCode.Boolean: return this.unionVal.boolVal;
204 case TypeCode.Int32: return valueConverter.ToBoolean(this.unionVal.i32Val);
205 case TypeCode.Int64: return valueConverter.ToBoolean(this.unionVal.i64Val);
206 case TypeCode.Double: return valueConverter.ToBoolean(this.unionVal.dblVal);
207 case TypeCode.DateTime: return valueConverter.ToBoolean(this.unionVal.dtVal);
208 default: Debug.Assert(false, "Should never get here"); break;
212 return valueConverter.ToBoolean(this.objVal);
216 public override DateTime ValueAsDateTime {
218 XmlValueConverter valueConverter = this.xmlType.ValueConverter;
220 if (this.objVal == null) {
221 switch (this.clrType) {
222 case TypeCode.Boolean: return valueConverter.ToDateTime(this.unionVal.boolVal);
223 case TypeCode.Int32: return valueConverter.ToDateTime(this.unionVal.i32Val);
224 case TypeCode.Int64: return valueConverter.ToDateTime(this.unionVal.i64Val);
225 case TypeCode.Double: return valueConverter.ToDateTime(this.unionVal.dblVal);
226 case TypeCode.DateTime: return this.unionVal.dtVal;
227 default: Debug.Assert(false, "Should never get here"); break;
231 return valueConverter.ToDateTime(this.objVal);
236 public override double ValueAsDouble {
238 XmlValueConverter valueConverter = this.xmlType.ValueConverter;
240 if (this.objVal == null) {
241 switch (this.clrType) {
242 case TypeCode.Boolean: return valueConverter.ToDouble(this.unionVal.boolVal);
243 case TypeCode.Int32: return valueConverter.ToDouble(this.unionVal.i32Val);
244 case TypeCode.Int64: return valueConverter.ToDouble(this.unionVal.i64Val);
245 case TypeCode.Double: return this.unionVal.dblVal;
246 case TypeCode.DateTime: return valueConverter.ToDouble(this.unionVal.dtVal);
247 default: Debug.Assert(false, "Should never get here"); break;
251 return valueConverter.ToDouble(this.objVal);
255 public override int ValueAsInt {
257 XmlValueConverter valueConverter = this.xmlType.ValueConverter;
259 if (this.objVal == null) {
260 switch (this.clrType) {
261 case TypeCode.Boolean: return valueConverter.ToInt32(this.unionVal.boolVal);
262 case TypeCode.Int32: return this.unionVal.i32Val;
263 case TypeCode.Int64: return valueConverter.ToInt32(this.unionVal.i64Val);
264 case TypeCode.Double: return valueConverter.ToInt32(this.unionVal.dblVal);
265 case TypeCode.DateTime: return valueConverter.ToInt32(this.unionVal.dtVal);
266 default: Debug.Assert(false, "Should never get here"); break;
270 return valueConverter.ToInt32(this.objVal);
274 public override long ValueAsLong {
276 XmlValueConverter valueConverter = this.xmlType.ValueConverter;
278 if (this.objVal == null) {
279 switch (this.clrType) {
280 case TypeCode.Boolean: return valueConverter.ToInt64(this.unionVal.boolVal);
281 case TypeCode.Int32: return valueConverter.ToInt64(this.unionVal.i32Val);
282 case TypeCode.Int64: return this.unionVal.i64Val;
283 case TypeCode.Double: return valueConverter.ToInt64(this.unionVal.dblVal);
284 case TypeCode.DateTime: return valueConverter.ToInt64(this.unionVal.dtVal);
285 default: Debug.Assert(false, "Should never get here"); break;
289 return valueConverter.ToInt64(this.objVal);
293 public override object ValueAs(Type type, IXmlNamespaceResolver nsResolver) {
294 XmlValueConverter valueConverter = this.xmlType.ValueConverter;
296 if (type == typeof(XPathItem) || type == typeof(XmlAtomicValue))
299 if (this.objVal == null) {
300 switch (this.clrType) {
301 case TypeCode.Boolean: return valueConverter.ChangeType(this.unionVal.boolVal, type);
302 case TypeCode.Int32: return valueConverter.ChangeType(this.unionVal.i32Val, type);
303 case TypeCode.Int64: return valueConverter.ChangeType(this.unionVal.i64Val, type);
304 case TypeCode.Double: return valueConverter.ChangeType(this.unionVal.dblVal, type);
305 case TypeCode.DateTime: return valueConverter.ChangeType(this.unionVal.dtVal, type);
306 default: Debug.Assert(false, "Should never get here"); break;
310 return valueConverter.ChangeType(this.objVal, type, nsResolver);
313 public override string Value {
315 XmlValueConverter valueConverter = this.xmlType.ValueConverter;
317 if (this.objVal == null) {
318 switch (this.clrType) {
319 case TypeCode.Boolean: return valueConverter.ToString(this.unionVal.boolVal);
320 case TypeCode.Int32: return valueConverter.ToString(this.unionVal.i32Val);
321 case TypeCode.Int64: return valueConverter.ToString(this.unionVal.i64Val);
322 case TypeCode.Double: return valueConverter.ToString(this.unionVal.dblVal);
323 case TypeCode.DateTime: return valueConverter.ToString(this.unionVal.dtVal);
324 default: Debug.Assert(false, "Should never get here"); break;
327 return valueConverter.ToString(this.objVal, this.nsPrefix);
331 public override string ToString() {
335 private string GetPrefixFromQName(string value) {
337 int len = ValidateNames.ParseQName(value, 0, out colonOffset);
339 if (len == 0 || len != value.Length) {
342 if (colonOffset != 0) {
343 return value.Substring(0, colonOffset);