Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Data.SqlXml / System / Xml / Xsl / Runtime / XsltConvert.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="XsltConvert.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>                                                                
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
7 using System;
8 using System.Collections;
9 using System.Collections.Generic;
10 using System.Xml.XPath;
11 using System.Xml.Xsl;
12 using System.Xml.Schema;
13 using System.Diagnostics;
14 using System.ComponentModel;
15
16 namespace System.Xml.Xsl.Runtime {
17     using Res           = System.Xml.Utils.Res;
18
19     /// <summary>
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
24     ///      Xslt types.
25     ///   3. Internal type to external type: These are conversions from one of the five Xslt types to any of
26     ///      of the Xsd types.
27     /// </summary>
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);
59
60
61         //------------------------------------------------------------------------
62         // ToBoolean (internal type to internal type)
63         //------------------------------------------------------------------------
64
65         public static bool ToBoolean(XPathItem item) {
66             XsltLibrary.CheckXsltValue(item);
67
68             if (item.IsNode)
69                 return true;
70
71             Type itemType = item.ValueType;
72
73             if (itemType == StringType) {
74                 return item.Value.Length != 0;
75             }
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;
80             }
81             else {
82                 Debug.Assert(itemType == BooleanType, "Unexpected type of atomic sequence " + itemType.ToString());
83                 return item.ValueAsBoolean;
84             }
85         }
86
87         public static bool ToBoolean(IList<XPathItem> listItems) {
88             XsltLibrary.CheckXsltValue(listItems);
89
90             if (listItems.Count == 0)
91                 return false;
92
93             return ToBoolean(listItems[0]);
94         }
95
96
97         //------------------------------------------------------------------------
98         // ToDouble (internal type to internal type)
99         //------------------------------------------------------------------------
100
101         public static double ToDouble(string value) {
102             return XPathConvert.StringToDouble(value);
103         }
104
105         public static double ToDouble(XPathItem item) {
106             XsltLibrary.CheckXsltValue(item);
107
108             if (item.IsNode)
109                 return XPathConvert.StringToDouble(item.Value);
110
111             Type itemType = item.ValueType;
112
113             if (itemType == StringType) {
114                 return XPathConvert.StringToDouble(item.Value);
115             }
116             else if (itemType == DoubleType) {
117                 return item.ValueAsDouble;
118             }
119             else {
120                 Debug.Assert(itemType == BooleanType, "Unexpected type of atomic sequence " + itemType.ToString());
121                 return item.ValueAsBoolean ? 1d : 0d;
122             }
123         }
124
125         public static double ToDouble(IList<XPathItem> listItems) {
126             XsltLibrary.CheckXsltValue(listItems);
127
128             if (listItems.Count == 0)
129                 return Double.NaN;
130
131             return ToDouble(listItems[0]);
132         }
133
134
135         //------------------------------------------------------------------------
136         // ToNode (internal type to internal type)
137         //------------------------------------------------------------------------
138
139         public static XPathNavigator ToNode(XPathItem item) {
140             XsltLibrary.CheckXsltValue(item);
141
142             if (!item.IsNode) {
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));
147                 writer.Close();
148                 return doc.CreateNavigator();
149             }
150
151             RtfNavigator rtf = item as RtfNavigator;
152             if (rtf != null)
153                 return rtf.ToNavigator();
154
155             return (XPathNavigator) item;
156         }
157
158         public static XPathNavigator ToNode(IList<XPathItem> listItems) {
159             XsltLibrary.CheckXsltValue(listItems);
160
161             if (listItems.Count == 1)
162                 return ToNode(listItems[0]);
163
164             throw new XslTransformException(Res.Xslt_NodeSetNotNode, string.Empty);
165         }
166
167
168         //------------------------------------------------------------------------
169         // ToNodes (internal type to internal type)
170         //------------------------------------------------------------------------
171
172         public static IList<XPathNavigator> ToNodeSet(XPathItem item) {
173             return new XmlQueryNodeSequence(ToNode(item));
174         }
175
176         public static IList<XPathNavigator> ToNodeSet(IList<XPathItem> listItems) {
177             XsltLibrary.CheckXsltValue(listItems);
178
179             if (listItems.Count == 1)
180                 return new XmlQueryNodeSequence(ToNode(listItems[0]));
181
182             return XmlILStorageConverter.ItemsToNavigators(listItems);
183         }
184
185
186         //------------------------------------------------------------------------
187         // ToString (internal type to internal type)
188         //------------------------------------------------------------------------
189
190         public static string ToString(double value) {
191             return XPathConvert.DoubleToString(value);
192         }
193
194         public static string ToString(XPathItem item) {
195             XsltLibrary.CheckXsltValue(item);
196
197             // Use XPath 1.0 rules to convert double to string
198             if (!item.IsNode && item.ValueType == DoubleType)
199                 return XPathConvert.DoubleToString(item.ValueAsDouble);
200
201             return item.Value;
202         }
203
204         public static string ToString(IList<XPathItem> listItems) {
205             XsltLibrary.CheckXsltValue(listItems);
206
207             if (listItems.Count == 0)
208                 return string.Empty;
209
210             return ToString(listItems[0]);
211         }
212
213
214         //------------------------------------------------------------------------
215         // External type to internal type
216         //------------------------------------------------------------------------
217
218         public static string ToString(DateTime value) {
219             return (new XsdDateTime(value, XsdDateTimeFlags.DateTime)).ToString();
220         }
221
222         public static double ToDouble(decimal value) {
223             return (double) value;
224         }
225
226         public static double ToDouble(int value) {
227             return (double) value;
228         }
229
230         public static double ToDouble(long value) {
231             return (double) value;
232         }
233
234
235         //------------------------------------------------------------------------
236         // Internal type to external type
237         //------------------------------------------------------------------------
238
239         public static decimal ToDecimal(double value) {
240             checked { return (decimal) value; }
241         }
242
243         public static int ToInt(double value) {
244             checked { return (int) value; }
245         }
246
247         public static long ToLong(double value) {
248             checked { return (long) value; }
249         }
250
251         public static DateTime ToDateTime(string value) {
252             return (DateTime)(new XsdDateTime(value, XsdDateTimeFlags.AllXsd));
253         }
254
255
256         //------------------------------------------------------------------------
257         // External type to external type
258         //------------------------------------------------------------------------
259
260         internal static XmlAtomicValue ConvertToType(XmlAtomicValue value, XmlQueryType destinationType) {
261             Debug.Assert(destinationType.IsStrict && destinationType.IsAtomicValue, "Can only convert to strict atomic type.");
262
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));
271                     }
272                     break;
273
274                 case XmlTypeCode.DateTime:
275                     if (value.XmlType.TypeCode == XmlTypeCode.String)
276                         return new XmlAtomicValue(destinationType.SchemaType, ToDateTime(value.Value));
277                     break;
278
279                 case XmlTypeCode.Decimal:
280                     if (value.XmlType.TypeCode == XmlTypeCode.Double)
281                         return new XmlAtomicValue(destinationType.SchemaType, ToDecimal(value.ValueAsDouble));
282                     break;
283
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));
290
291                         case XmlTypeCode.Decimal:
292                             return new XmlAtomicValue(destinationType.SchemaType, ToDouble((decimal) value.ValueAs(DecimalType, null)));
293
294                         case XmlTypeCode.Int:
295                         case XmlTypeCode.Long:
296                             return new XmlAtomicValue(destinationType.SchemaType, ToDouble(value.ValueAsLong));
297                     }
298                     break;
299
300                 case XmlTypeCode.Int:
301                 case XmlTypeCode.Long:
302                     if (value.XmlType.TypeCode == XmlTypeCode.Double)
303                         return new XmlAtomicValue(destinationType.SchemaType, ToLong(value.ValueAsDouble));
304                     break;
305
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));
312
313                         case XmlTypeCode.DateTime:
314                             return new XmlAtomicValue(destinationType.SchemaType, ToString(value.ValueAsDateTime));
315                     }
316                     break;
317             }
318
319             Debug.Fail("Conversion from " + value.XmlType.QualifiedName.Name + " to " + destinationType + " is not supported.");
320             return value;
321         }
322
323
324         //------------------------------------------------------------------------
325         // EnsureXXX methods (TreatAs)
326         //------------------------------------------------------------------------
327
328         public static IList<XPathNavigator> EnsureNodeSet(IList<XPathItem> listItems) {
329             XsltLibrary.CheckXsltValue(listItems);
330
331             if (listItems.Count == 1) {
332                 XPathItem item = listItems[0];
333                 if (!item.IsNode)
334                     throw new XslTransformException(Res.XPath_NodeSetExpected, string.Empty);
335
336                 if (item is RtfNavigator)
337                     throw new XslTransformException(Res.XPath_RtfInPathExpr, string.Empty);
338             }
339
340             return XmlILStorageConverter.ItemsToNavigators(listItems);
341         }
342
343
344         //------------------------------------------------------------------------
345         // InferXsltType
346         //------------------------------------------------------------------------
347
348         /// <summary>
349         /// Infer one of the Xslt types from "clrType" -- Boolean, Double, String, Node, Node*, Item*.
350         /// </summary>
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;
372
373             return XmlQueryTypeFactory.ItemS;
374         }
375     }
376 }