1 //------------------------------------------------------------------------------
2 // <copyright file="XsltConvert.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
8 using System.Collections;
9 using System.Collections.Generic;
10 using System.Xml.XPath;
12 using System.Xml.Schema;
13 using System.Diagnostics;
14 using System.ComponentModel;
16 namespace System.Xml.Xsl.Runtime {
17 using Res = System.Xml.Utils.Res;
20 /// Contains conversion routines used by Xslt. These conversions fall into several categories:
21 /// 1. Internal type to internal type: These are conversions from one of the five Xslt types to another
22 /// of the five types.
23 /// 2. External type to internal type: These are conversions from any of the Xsd types to one of the five
25 /// 3. Internal type to external type: These are conversions from one of the five Xslt types to any of
28 [EditorBrowsable(EditorBrowsableState.Never)]
29 public static class XsltConvert {
30 internal static readonly Type BooleanType = typeof(bool);
31 internal static readonly Type ByteArrayType = typeof(byte[]);
32 internal static readonly Type ByteType = typeof(byte);
33 internal static readonly Type DateTimeType = typeof(DateTime);
34 internal static readonly Type DecimalType = typeof(decimal);
35 internal static readonly Type DoubleType = typeof(double);
36 internal static readonly Type ICollectionType = typeof(ICollection);
37 internal static readonly Type IEnumerableType = typeof(IEnumerable);
38 internal static readonly Type IListType = typeof(IList);
39 internal static readonly Type Int16Type = typeof(short);
40 internal static readonly Type Int32Type = typeof(int);
41 internal static readonly Type Int64Type = typeof(long);
42 internal static readonly Type IXPathNavigableType = typeof(IXPathNavigable);
43 internal static readonly Type ObjectType = typeof(object);
44 internal static readonly Type SByteType = typeof(sbyte);
45 internal static readonly Type SingleType = typeof(float);
46 internal static readonly Type StringType = typeof(string);
47 internal static readonly Type TimeSpanType = typeof(TimeSpan);
48 internal static readonly Type UInt16Type = typeof(ushort);
49 internal static readonly Type UInt32Type = typeof(uint);
50 internal static readonly Type UInt64Type = typeof(ulong);
51 internal static readonly Type UriType = typeof(Uri);
52 internal static readonly Type VoidType = typeof(void);
53 internal static readonly Type XmlAtomicValueType = typeof(XmlAtomicValue);
54 internal static readonly Type XmlQualifiedNameType = typeof(XmlQualifiedName);
55 internal static readonly Type XPathItemType = typeof(XPathItem);
56 internal static readonly Type XPathNavigatorArrayType = typeof(XPathNavigator[]);
57 internal static readonly Type XPathNavigatorType = typeof(XPathNavigator);
58 internal static readonly Type XPathNodeIteratorType = typeof(XPathNodeIterator);
61 //------------------------------------------------------------------------
62 // ToBoolean (internal type to internal type)
63 //------------------------------------------------------------------------
65 public static bool ToBoolean(XPathItem item) {
66 XsltLibrary.CheckXsltValue(item);
71 Type itemType = item.ValueType;
73 if (itemType == StringType) {
74 return item.Value.Length != 0;
76 else if (itemType == DoubleType) {
77 // (x < 0 || 0 < x) == (x != 0) && !Double.IsNaN(x)
78 double dbl = item.ValueAsDouble;
79 return dbl < 0 || 0 < dbl;
82 Debug.Assert(itemType == BooleanType, "Unexpected type of atomic sequence " + itemType.ToString());
83 return item.ValueAsBoolean;
87 public static bool ToBoolean(IList<XPathItem> listItems) {
88 XsltLibrary.CheckXsltValue(listItems);
90 if (listItems.Count == 0)
93 return ToBoolean(listItems[0]);
97 //------------------------------------------------------------------------
98 // ToDouble (internal type to internal type)
99 //------------------------------------------------------------------------
101 public static double ToDouble(string value) {
102 return XPathConvert.StringToDouble(value);
105 public static double ToDouble(XPathItem item) {
106 XsltLibrary.CheckXsltValue(item);
109 return XPathConvert.StringToDouble(item.Value);
111 Type itemType = item.ValueType;
113 if (itemType == StringType) {
114 return XPathConvert.StringToDouble(item.Value);
116 else if (itemType == DoubleType) {
117 return item.ValueAsDouble;
120 Debug.Assert(itemType == BooleanType, "Unexpected type of atomic sequence " + itemType.ToString());
121 return item.ValueAsBoolean ? 1d : 0d;
125 public static double ToDouble(IList<XPathItem> listItems) {
126 XsltLibrary.CheckXsltValue(listItems);
128 if (listItems.Count == 0)
131 return ToDouble(listItems[0]);
135 //------------------------------------------------------------------------
136 // ToNode (internal type to internal type)
137 //------------------------------------------------------------------------
139 public static XPathNavigator ToNode(XPathItem item) {
140 XsltLibrary.CheckXsltValue(item);
143 // Create Navigator over text node containing string value of item
144 XPathDocument doc = new XPathDocument();
145 XmlRawWriter writer = doc.LoadFromWriter(XPathDocument.LoadFlags.AtomizeNames, string.Empty);
146 writer.WriteString(ToString(item));
148 return doc.CreateNavigator();
151 RtfNavigator rtf = item as RtfNavigator;
153 return rtf.ToNavigator();
155 return (XPathNavigator) item;
158 public static XPathNavigator ToNode(IList<XPathItem> listItems) {
159 XsltLibrary.CheckXsltValue(listItems);
161 if (listItems.Count == 1)
162 return ToNode(listItems[0]);
164 throw new XslTransformException(Res.Xslt_NodeSetNotNode, string.Empty);
168 //------------------------------------------------------------------------
169 // ToNodes (internal type to internal type)
170 //------------------------------------------------------------------------
172 public static IList<XPathNavigator> ToNodeSet(XPathItem item) {
173 return new XmlQueryNodeSequence(ToNode(item));
176 public static IList<XPathNavigator> ToNodeSet(IList<XPathItem> listItems) {
177 XsltLibrary.CheckXsltValue(listItems);
179 if (listItems.Count == 1)
180 return new XmlQueryNodeSequence(ToNode(listItems[0]));
182 return XmlILStorageConverter.ItemsToNavigators(listItems);
186 //------------------------------------------------------------------------
187 // ToString (internal type to internal type)
188 //------------------------------------------------------------------------
190 public static string ToString(double value) {
191 return XPathConvert.DoubleToString(value);
194 public static string ToString(XPathItem item) {
195 XsltLibrary.CheckXsltValue(item);
197 // Use XPath 1.0 rules to convert double to string
198 if (!item.IsNode && item.ValueType == DoubleType)
199 return XPathConvert.DoubleToString(item.ValueAsDouble);
204 public static string ToString(IList<XPathItem> listItems) {
205 XsltLibrary.CheckXsltValue(listItems);
207 if (listItems.Count == 0)
210 return ToString(listItems[0]);
214 //------------------------------------------------------------------------
215 // External type to internal type
216 //------------------------------------------------------------------------
218 public static string ToString(DateTime value) {
219 return (new XsdDateTime(value, XsdDateTimeFlags.DateTime)).ToString();
222 public static double ToDouble(decimal value) {
223 return (double) value;
226 public static double ToDouble(int value) {
227 return (double) value;
230 public static double ToDouble(long value) {
231 return (double) value;
235 //------------------------------------------------------------------------
236 // Internal type to external type
237 //------------------------------------------------------------------------
239 public static decimal ToDecimal(double value) {
240 checked { return (decimal) value; }
243 public static int ToInt(double value) {
244 checked { return (int) value; }
247 public static long ToLong(double value) {
248 checked { return (long) value; }
251 public static DateTime ToDateTime(string value) {
252 return (DateTime)(new XsdDateTime(value, XsdDateTimeFlags.AllXsd));
256 //------------------------------------------------------------------------
257 // External type to external type
258 //------------------------------------------------------------------------
260 internal static XmlAtomicValue ConvertToType(XmlAtomicValue value, XmlQueryType destinationType) {
261 Debug.Assert(destinationType.IsStrict && destinationType.IsAtomicValue, "Can only convert to strict atomic type.");
263 // This conversion matrix should match the one in XmlILVisitor.GetXsltConvertMethod
264 switch (destinationType.TypeCode) {
265 case XmlTypeCode.Boolean:
266 switch (value.XmlType.TypeCode) {
267 case XmlTypeCode.Boolean:
268 case XmlTypeCode.Double:
269 case XmlTypeCode.String:
270 return new XmlAtomicValue(destinationType.SchemaType, ToBoolean(value));
274 case XmlTypeCode.DateTime:
275 if (value.XmlType.TypeCode == XmlTypeCode.String)
276 return new XmlAtomicValue(destinationType.SchemaType, ToDateTime(value.Value));
279 case XmlTypeCode.Decimal:
280 if (value.XmlType.TypeCode == XmlTypeCode.Double)
281 return new XmlAtomicValue(destinationType.SchemaType, ToDecimal(value.ValueAsDouble));
284 case XmlTypeCode.Double:
285 switch (value.XmlType.TypeCode) {
286 case XmlTypeCode.Boolean:
287 case XmlTypeCode.Double:
288 case XmlTypeCode.String:
289 return new XmlAtomicValue(destinationType.SchemaType, ToDouble(value));
291 case XmlTypeCode.Decimal:
292 return new XmlAtomicValue(destinationType.SchemaType, ToDouble((decimal) value.ValueAs(DecimalType, null)));
294 case XmlTypeCode.Int:
295 case XmlTypeCode.Long:
296 return new XmlAtomicValue(destinationType.SchemaType, ToDouble(value.ValueAsLong));
300 case XmlTypeCode.Int:
301 case XmlTypeCode.Long:
302 if (value.XmlType.TypeCode == XmlTypeCode.Double)
303 return new XmlAtomicValue(destinationType.SchemaType, ToLong(value.ValueAsDouble));
306 case XmlTypeCode.String:
307 switch (value.XmlType.TypeCode) {
308 case XmlTypeCode.Boolean:
309 case XmlTypeCode.Double:
310 case XmlTypeCode.String:
311 return new XmlAtomicValue(destinationType.SchemaType, ToString(value));
313 case XmlTypeCode.DateTime:
314 return new XmlAtomicValue(destinationType.SchemaType, ToString(value.ValueAsDateTime));
319 Debug.Fail("Conversion from " + value.XmlType.QualifiedName.Name + " to " + destinationType + " is not supported.");
324 //------------------------------------------------------------------------
325 // EnsureXXX methods (TreatAs)
326 //------------------------------------------------------------------------
328 public static IList<XPathNavigator> EnsureNodeSet(IList<XPathItem> listItems) {
329 XsltLibrary.CheckXsltValue(listItems);
331 if (listItems.Count == 1) {
332 XPathItem item = listItems[0];
334 throw new XslTransformException(Res.XPath_NodeSetExpected, string.Empty);
336 if (item is RtfNavigator)
337 throw new XslTransformException(Res.XPath_RtfInPathExpr, string.Empty);
340 return XmlILStorageConverter.ItemsToNavigators(listItems);
344 //------------------------------------------------------------------------
346 //------------------------------------------------------------------------
349 /// Infer one of the Xslt types from "clrType" -- Boolean, Double, String, Node, Node*, Item*.
351 internal static XmlQueryType InferXsltType(Type clrType) {
352 if (clrType == BooleanType) return XmlQueryTypeFactory.BooleanX;
353 if (clrType == ByteType) return XmlQueryTypeFactory.DoubleX;
354 if (clrType == DecimalType) return XmlQueryTypeFactory.DoubleX;
355 if (clrType == DateTimeType) return XmlQueryTypeFactory.StringX;
356 if (clrType == DoubleType) return XmlQueryTypeFactory.DoubleX;
357 if (clrType == Int16Type) return XmlQueryTypeFactory.DoubleX;
358 if (clrType == Int32Type) return XmlQueryTypeFactory.DoubleX;
359 if (clrType == Int64Type) return XmlQueryTypeFactory.DoubleX;
360 if (clrType == IXPathNavigableType) return XmlQueryTypeFactory.NodeNotRtf;
361 if (clrType == SByteType) return XmlQueryTypeFactory.DoubleX;
362 if (clrType == SingleType) return XmlQueryTypeFactory.DoubleX;
363 if (clrType == StringType) return XmlQueryTypeFactory.StringX;
364 if (clrType == UInt16Type) return XmlQueryTypeFactory.DoubleX;
365 if (clrType == UInt32Type) return XmlQueryTypeFactory.DoubleX;
366 if (clrType == UInt64Type) return XmlQueryTypeFactory.DoubleX;
367 if (clrType == XPathNavigatorArrayType) return XmlQueryTypeFactory.NodeSDod;
368 if (clrType == XPathNavigatorType) return XmlQueryTypeFactory.NodeNotRtf;
369 if (clrType == XPathNodeIteratorType) return XmlQueryTypeFactory.NodeSDod;
370 if (clrType.IsEnum) return XmlQueryTypeFactory.DoubleX;
371 if (clrType == VoidType) return XmlQueryTypeFactory.Empty;
373 return XmlQueryTypeFactory.ItemS;