private static bool CompareValues(ComparisonOperator op, XPathItem left, XPathItem right, TypeCode compType) { if (compType == TypeCode.Double) { return(CompareNumbers(op, XsltConvert.ToDouble(left), XsltConvert.ToDouble(right))); } else { Debug.Assert(op == ComparisonOperator.Eq || op == ComparisonOperator.Ne); if (compType == TypeCode.String) { return((XsltConvert.ToString(left) == XsltConvert.ToString(right)) == (op == ComparisonOperator.Eq)); } else { Debug.Assert(compType == TypeCode.Boolean); return((XsltConvert.ToBoolean(left) == XsltConvert.ToBoolean(right)) == (op == ComparisonOperator.Eq)); } } }
/// <summary> /// Convert from the Clr type of "value" to the default Clr type that ILGen uses to represent the xml type, using /// the conversion rules of the xml type. /// </summary> internal object ChangeTypeXsltResult(XmlQueryType xmlType, object value) { if (value == null) { throw new XslTransformException(SR.Xslt_ItemNull, string.Empty); } switch (xmlType.TypeCode) { case XmlTypeCode.String: if (value.GetType() == XsltConvert.DateTimeType) { value = XsltConvert.ToString((DateTime)value); } break; case XmlTypeCode.Double: if (value.GetType() != XsltConvert.DoubleType) { value = ((IConvertible)value).ToDouble(null); } break; case XmlTypeCode.Node: if (!xmlType.IsSingleton) { XPathArrayIterator iter = value as XPathArrayIterator; // Special-case XPathArrayIterator in order to avoid copies if (iter != null && iter.AsList is XmlQueryNodeSequence) { value = iter.AsList as XmlQueryNodeSequence; } else { // Iterate over list and ensure it only contains nodes XmlQueryNodeSequence seq = new XmlQueryNodeSequence(); IList list = value as IList; if (list != null) { for (int i = 0; i < list.Count; i++) { seq.Add(EnsureNavigator(list[i])); } } else { foreach (object o in (IEnumerable)value) { seq.Add(EnsureNavigator(o)); } } value = seq; } // Always sort node-set by document order value = ((XmlQueryNodeSequence)value).DocOrderDistinct(_docOrderCmp); } break; case XmlTypeCode.Item: { Type sourceType = value.GetType(); IXPathNavigable navigable; // If static type is item, then infer type based on dynamic value switch (XsltConvert.InferXsltType(sourceType).TypeCode) { case XmlTypeCode.Boolean: value = new XmlQueryItemSequence(new XmlAtomicValue(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.Boolean), value)); break; case XmlTypeCode.Double: value = new XmlQueryItemSequence(new XmlAtomicValue(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.Double), ((IConvertible)value).ToDouble(null))); break; case XmlTypeCode.String: if (sourceType == XsltConvert.DateTimeType) { value = new XmlQueryItemSequence(new XmlAtomicValue(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.String), XsltConvert.ToString((DateTime)value))); } else { value = new XmlQueryItemSequence(new XmlAtomicValue(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.String), value)); } break; case XmlTypeCode.Node: // Support XPathNavigator[] value = ChangeTypeXsltResult(XmlQueryTypeFactory.NodeS, value); break; case XmlTypeCode.Item: // Support XPathNodeIterator if (value is XPathNodeIterator) { value = ChangeTypeXsltResult(XmlQueryTypeFactory.NodeS, value); break; } // Support IXPathNavigable and XPathNavigator navigable = value as IXPathNavigable; if (navigable != null) { if (value is XPathNavigator) { value = new XmlQueryNodeSequence((XPathNavigator)value); } else { value = new XmlQueryNodeSequence(navigable.CreateNavigator()); } break; } throw new XslTransformException(SR.Xslt_UnsupportedClrType, sourceType.Name); } break; } } #if FEATURE_COMPILED_XSL Debug.Assert(XmlILTypeHelper.GetStorageType(xmlType).IsAssignableFrom(value.GetType()), "Xml type " + xmlType + " is not represented in ILGen as " + value.GetType().Name); #endif return(value); }
/// <summary> /// Get a late-bound extension object from the external argument list. Bind to a method on the object and invoke it, /// passing "args" as arguments. /// </summary> public IList <XPathItem> InvokeXsltLateBoundFunction(string name, string namespaceUri, IList <XPathItem>[] args) { object instance; object[] objActualArgs; XmlQueryType xmlTypeFormalArg; Type clrTypeFormalArg; object objRet; // Get external object instance from argument list (throw if either the list or the instance doesn't exist) instance = (_argList != null) ? _argList.GetExtensionObject(namespaceUri) : null; if (instance == null) { throw new XslTransformException(SR.XmlIl_UnknownExtObj, namespaceUri); } // Bind to a method on the instance object if (_extFuncsLate == null) { _extFuncsLate = new XmlExtensionFunctionTable(); } // Bind to the instance, looking for a matching method (throws if no matching method) XmlExtensionFunction extFunc = _extFuncsLate.Bind(name, namespaceUri, args.Length, instance.GetType(), XmlQueryRuntime.LateBoundFlags); // Create array which will contain the actual arguments objActualArgs = new object[args.Length]; for (int i = 0; i < args.Length; i++) { // 1. Assume that the input value can only have one of the following 5 Xslt types: // xs:double, xs:string, xs:boolean, node* (can be rtf) // 2. Convert each Rtf value to a NodeSet containing one node. Now the value may only have one of the 4 Xslt types. // 3. Convert from one of the 4 Xslt internal types to the Xslt internal type which is closest to the formal // argument's Xml type (inferred from the Clr type of the formal argument). xmlTypeFormalArg = extFunc.GetXmlArgumentType(i); switch (xmlTypeFormalArg.TypeCode) { case XmlTypeCode.Boolean: objActualArgs[i] = XsltConvert.ToBoolean(args[i]); break; case XmlTypeCode.Double: objActualArgs[i] = XsltConvert.ToDouble(args[i]); break; case XmlTypeCode.String: objActualArgs[i] = XsltConvert.ToString(args[i]); break; case XmlTypeCode.Node: if (xmlTypeFormalArg.IsSingleton) { objActualArgs[i] = XsltConvert.ToNode(args[i]); } else { objActualArgs[i] = XsltConvert.ToNodeSet(args[i]); } break; case XmlTypeCode.Item: objActualArgs[i] = args[i]; break; default: Debug.Fail("This XmlTypeCode should never be inferred from a Clr type: " + xmlTypeFormalArg.TypeCode); break; } // 4. Change the Clr representation to the Clr type of the formal argument clrTypeFormalArg = extFunc.GetClrArgumentType(i); if (xmlTypeFormalArg.TypeCode == XmlTypeCode.Item || !clrTypeFormalArg.IsAssignableFrom(objActualArgs[i].GetType())) { objActualArgs[i] = _runtime.ChangeTypeXsltArgument(xmlTypeFormalArg, objActualArgs[i], clrTypeFormalArg); } } // 1. Invoke the late bound method objRet = extFunc.Invoke(instance, objActualArgs); // 2. Convert to IList<XPathItem> if (objRet == null && extFunc.ClrReturnType == XsltConvert.VoidType) { return(XmlQueryNodeSequence.Empty); } return((IList <XPathItem>)_runtime.ChangeTypeXsltResult(XmlQueryTypeFactory.ItemS, objRet)); }