| File: System\Xml\Xsl\Runtime\XsltConvert.cs | Web Access |
| Project: src\runtime\src\libraries\System.Private.Xml\src\System.Private.Xml.csproj (System.Private.Xml) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Xml.Schema; using System.Xml.XPath; namespace System.Xml.Xsl.Runtime { /// <summary> /// Contains conversion routines used by Xslt. These conversions fall into several categories: /// 1. Internal type to internal type: These are conversions from one of the five Xslt types to another /// of the five types. /// 2. External type to internal type: These are conversions from any of the Xsd types to one of the five /// Xslt types. /// 3. Internal type to external type: These are conversions from one of the five Xslt types to any of /// of the Xsd types. /// </summary> [EditorBrowsable(EditorBrowsableState.Never)] public static class XsltConvert { //------------------------------------------------------------------------ // ToBoolean (internal type to internal type) //------------------------------------------------------------------------ public static bool ToBoolean(XPathItem item) { XsltLibrary.CheckXsltValue(item); if (item.IsNode) return true; Type itemType = item.ValueType; if (itemType == typeof(string)) { return item.Value.Length != 0; } else if (itemType == typeof(double)) { // (x < 0 || 0 < x) == (x != 0) && !Double.IsNaN(x) double dbl = item.ValueAsDouble; return dbl < 0 || 0 < dbl; } else { Debug.Assert(itemType == typeof(bool), $"Unexpected type of atomic sequence {itemType}"); return item.ValueAsBoolean; } } public static bool ToBoolean(IList<XPathItem> listItems) { XsltLibrary.CheckXsltValue(listItems); if (listItems.Count == 0) return false; return ToBoolean(listItems[0]); } //------------------------------------------------------------------------ // ToDouble (internal type to internal type) //------------------------------------------------------------------------ public static double ToDouble(string value) { return XPathConvert.StringToDouble(value); } public static double ToDouble(XPathItem item) { XsltLibrary.CheckXsltValue(item); if (item.IsNode) return XPathConvert.StringToDouble(item.Value); Type itemType = item.ValueType; if (itemType == typeof(string)) { return XPathConvert.StringToDouble(item.Value); } else if (itemType == typeof(double)) { return item.ValueAsDouble; } else { Debug.Assert(itemType == typeof(bool), $"Unexpected type of atomic sequence {itemType}"); return item.ValueAsBoolean ? 1d : 0d; } } public static double ToDouble(IList<XPathItem> listItems) { XsltLibrary.CheckXsltValue(listItems); if (listItems.Count == 0) return double.NaN; return ToDouble(listItems[0]); } //------------------------------------------------------------------------ // ToNode (internal type to internal type) //------------------------------------------------------------------------ public static XPathNavigator ToNode(XPathItem item) { XsltLibrary.CheckXsltValue(item); if (!item.IsNode) { // Create Navigator over text node containing string value of item XPathDocument doc = new XPathDocument(); XmlRawWriter writer = doc.LoadFromWriter(XPathDocument.LoadFlags.AtomizeNames, string.Empty); writer.WriteString(ToString(item)); writer.Close(); return doc.CreateNavigator(); } RtfNavigator? rtf = item as RtfNavigator; if (rtf != null) return rtf.ToNavigator(); return (XPathNavigator)item; } public static XPathNavigator ToNode(IList<XPathItem> listItems) { XsltLibrary.CheckXsltValue(listItems); if (listItems.Count == 1) return ToNode(listItems[0]); throw new XslTransformException(SR.Xslt_NodeSetNotNode, string.Empty); } //------------------------------------------------------------------------ // ToNodes (internal type to internal type) //------------------------------------------------------------------------ public static IList<XPathNavigator> ToNodeSet(XPathItem item) { return new XmlQueryNodeSequence(ToNode(item)); } public static IList<XPathNavigator> ToNodeSet(IList<XPathItem> listItems) { XsltLibrary.CheckXsltValue(listItems); if (listItems.Count == 1) return new XmlQueryNodeSequence(ToNode(listItems[0])); return XmlILStorageConverter.ItemsToNavigators(listItems); } //------------------------------------------------------------------------ // ToString (internal type to internal type) //------------------------------------------------------------------------ public static string ToString(double value) { return XPathConvert.DoubleToString(value); } public static string ToString(XPathItem item) { XsltLibrary.CheckXsltValue(item); // Use XPath 1.0 rules to convert double to string if (!item.IsNode && item.ValueType == typeof(double)) return XPathConvert.DoubleToString(item.ValueAsDouble); return item.Value; } public static string ToString(IList<XPathItem> listItems) { XsltLibrary.CheckXsltValue(listItems); if (listItems.Count == 0) return string.Empty; return ToString(listItems[0]); } //------------------------------------------------------------------------ // External type to internal type //------------------------------------------------------------------------ public static string ToString(DateTime value) { return (new XsdDateTime(value, XsdDateTimeFlags.DateTime)).ToString(); } public static double ToDouble(decimal value) { return (double)value; } public static double ToDouble(int value) { return (double)value; } public static double ToDouble(long value) { return (double)value; } //------------------------------------------------------------------------ // Internal type to external type //------------------------------------------------------------------------ public static decimal ToDecimal(double value) { checked { return (decimal)value; } } public static int ToInt(double value) { checked { return (int)value; } } public static long ToLong(double value) { checked { return (long)value; } } public static DateTime ToDateTime(string value) { return (DateTime)(new XsdDateTime(value, XsdDateTimeFlags.AllXsd)); } //------------------------------------------------------------------------ // External type to external type //------------------------------------------------------------------------ internal static XmlAtomicValue ConvertToType(XmlAtomicValue value, XmlQueryType destinationType) { Debug.Assert(destinationType.IsStrict && destinationType.IsAtomicValue, "Can only convert to strict atomic type."); // This conversion matrix should match the one in XmlILVisitor.GetXsltConvertMethod switch (destinationType.TypeCode) { case XmlTypeCode.Boolean: switch (value.XmlType.TypeCode) { case XmlTypeCode.Boolean: case XmlTypeCode.Double: case XmlTypeCode.String: return new XmlAtomicValue(destinationType.SchemaType, ToBoolean(value)); } break; case XmlTypeCode.DateTime: if (value.XmlType.TypeCode == XmlTypeCode.String) return new XmlAtomicValue(destinationType.SchemaType, ToDateTime(value.Value)); break; case XmlTypeCode.Decimal: if (value.XmlType.TypeCode == XmlTypeCode.Double) return new XmlAtomicValue(destinationType.SchemaType, ToDecimal(value.ValueAsDouble)); break; case XmlTypeCode.Double: switch (value.XmlType.TypeCode) { case XmlTypeCode.Boolean: case XmlTypeCode.Double: case XmlTypeCode.String: return new XmlAtomicValue(destinationType.SchemaType, ToDouble(value)); case XmlTypeCode.Decimal: return new XmlAtomicValue(destinationType.SchemaType, ToDouble((decimal)value.ValueAs(typeof(decimal), null))); case XmlTypeCode.Int: case XmlTypeCode.Long: return new XmlAtomicValue(destinationType.SchemaType, ToDouble(value.ValueAsLong)); } break; case XmlTypeCode.Int: case XmlTypeCode.Long: if (value.XmlType.TypeCode == XmlTypeCode.Double) return new XmlAtomicValue(destinationType.SchemaType, ToLong(value.ValueAsDouble)); break; case XmlTypeCode.String: switch (value.XmlType.TypeCode) { case XmlTypeCode.Boolean: case XmlTypeCode.Double: case XmlTypeCode.String: return new XmlAtomicValue(destinationType.SchemaType, ToString(value)); case XmlTypeCode.DateTime: return new XmlAtomicValue(destinationType.SchemaType, ToString(value.ValueAsDateTime)); } break; } Debug.Fail($"Conversion from {value.XmlType.QualifiedName.Name} to {destinationType} is not supported."); return value; } //------------------------------------------------------------------------ // EnsureXXX methods (TreatAs) //------------------------------------------------------------------------ public static IList<XPathNavigator> EnsureNodeSet(IList<XPathItem> listItems) { XsltLibrary.CheckXsltValue(listItems); if (listItems.Count == 1) { XPathItem item = listItems[0]; if (!item.IsNode) throw new XslTransformException(SR.XPath_NodeSetExpected, string.Empty); if (item is RtfNavigator) throw new XslTransformException(SR.XPath_RtfInPathExpr, string.Empty); } return XmlILStorageConverter.ItemsToNavigators(listItems); } //------------------------------------------------------------------------ // InferXsltType //------------------------------------------------------------------------ /// <summary> /// Infer one of the Xslt types from "clrType" -- Boolean, Double, String, Node, Node*, Item*. /// </summary> internal static XmlQueryType InferXsltType(Type clrType) { if (clrType == typeof(bool)) return XmlQueryTypeFactory.BooleanX; if (clrType == typeof(byte)) return XmlQueryTypeFactory.DoubleX; if (clrType == typeof(decimal)) return XmlQueryTypeFactory.DoubleX; if (clrType == typeof(DateTime)) return XmlQueryTypeFactory.StringX; if (clrType == typeof(double)) return XmlQueryTypeFactory.DoubleX; if (clrType == typeof(short)) return XmlQueryTypeFactory.DoubleX; if (clrType == typeof(int)) return XmlQueryTypeFactory.DoubleX; if (clrType == typeof(long)) return XmlQueryTypeFactory.DoubleX; if (clrType == typeof(IXPathNavigable)) return XmlQueryTypeFactory.NodeNotRtf; if (clrType == typeof(sbyte)) return XmlQueryTypeFactory.DoubleX; if (clrType == typeof(float)) return XmlQueryTypeFactory.DoubleX; if (clrType == typeof(string)) return XmlQueryTypeFactory.StringX; if (clrType == typeof(ushort)) return XmlQueryTypeFactory.DoubleX; if (clrType == typeof(uint)) return XmlQueryTypeFactory.DoubleX; if (clrType == typeof(ulong)) return XmlQueryTypeFactory.DoubleX; if (clrType == typeof(XPathNavigator[])) return XmlQueryTypeFactory.NodeSDod; if (clrType == typeof(XPathNavigator)) return XmlQueryTypeFactory.NodeNotRtf; if (clrType == typeof(XPathNodeIterator)) return XmlQueryTypeFactory.NodeSDod; if (clrType.IsEnum) return XmlQueryTypeFactory.DoubleX; if (clrType == typeof(void)) return XmlQueryTypeFactory.Empty; return XmlQueryTypeFactory.ItemS; } } }