public XmlExtensionFunction Bind( string name, string namespaceUri, int numArgs, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] Type objectType, BindingFlags flags) { XmlExtensionFunction func; _funcCached ??= new XmlExtensionFunction(); // If the extension function already exists in the table, then binding has already been performed _funcCached.Init(name, namespaceUri, numArgs, objectType, flags); if (!_table.TryGetValue(_funcCached, out func)) { // Function doesn't exist, so bind it and enter it into the table func = _funcCached; _funcCached = null; func.Bind(); _table.Add(func, func); } return(func); }
/// <summary> /// Return true if this XmlExtensionFunction has the same values as another XmlExtensionFunction. /// </summary> public override bool Equals(object other) { XmlExtensionFunction that = other as XmlExtensionFunction; Debug.Assert(that != null); // Compare name, argument count, object type, and binding flags return(_hashCode == that._hashCode && _name == that._name && _namespaceUri == that._namespaceUri && _numArgs == that._numArgs && _objectType == that._objectType && _flags == that._flags); }
public XmlExtensionFunction Bind(string name, string namespaceUri, int numArgs, Type objectType, BindingFlags flags) { XmlExtensionFunction func; if (this.funcCached == null) this.funcCached = new XmlExtensionFunction(); // If the extension function already exists in the table, then binding has already been performed this.funcCached.Init(name, namespaceUri, numArgs, objectType, flags); if (!this.table.TryGetValue(this.funcCached, out func)) { // Function doesn't exist, so bind it and enter it into the table func = this.funcCached; this.funcCached = null; func.Bind(); this.table.Add(func, func); } return func; }
public XmlExtensionFunction Bind(string name, string namespaceUri, int numArgs, Type objectType, BindingFlags flags) { XmlExtensionFunction func; if (_funcCached == null) { _funcCached = new XmlExtensionFunction(); } // If the extension function already exists in the table, then binding has already been performed _funcCached.Init(name, namespaceUri, numArgs, objectType, flags); if (!_table.TryGetValue(_funcCached, out func)) { // Function doesn't exist, so bind it and enter it into the table func = _funcCached; _funcCached = null; func.Bind(); _table.Add(func, func); } return(func); }
public XmlQueryType CheckXsltInvokeEarlyBound(QilInvokeEarlyBound node) { #if DEBUG CheckLiteralValue(node[0], typeof(QilName)); CheckLiteralValue(node[1], typeof(MethodInfo)); CheckClassAndNodeType(node[2], typeof(QilList), QilNodeType.ActualParameterList); XmlExtensionFunction extFunc = new XmlExtensionFunction(node.Name.LocalName, node.Name.NamespaceUri, node.ClrMethod); QilList actualArgs = node.Arguments; Check(actualArgs.Count == extFunc.Method.GetParameters().Length, actualArgs, "InvokeEarlyBound argument count must match function's argument count"); for (int i = 0; i < actualArgs.Count; i++) { Check(actualArgs[i].XmlType.IsSubtypeOf(extFunc.GetXmlArgumentType(i)), actualArgs[i], "InvokeEarlyBound argument must be a subtype of the invoked function's argument type"); } #endif return node.XmlType; }
private QilNode GenerateScriptCall(QilName name, XmlExtensionFunction scrFunc, IList<QilNode> args) { XmlQueryType xmlTypeFormalArg; for (int i = 0; i < args.Count; i++) { xmlTypeFormalArg = scrFunc.GetXmlArgumentType(i); switch (xmlTypeFormalArg.TypeCode) { case XmlTypeCode.Boolean: args[i] = f.ConvertToBoolean(args[i]); break; case XmlTypeCode.Double: args[i] = f.ConvertToNumber(args[i]); break; case XmlTypeCode.String: args[i] = f.ConvertToString(args[i]); break; case XmlTypeCode.Node: args[i] = xmlTypeFormalArg.IsSingleton ? f.ConvertToNode(args[i]) : f.ConvertToNodeSet(args[i]); break; case XmlTypeCode.Item: break; default: Debug.Fail("This XmlTypeCode should never be inferred from a Clr type: " + xmlTypeFormalArg.TypeCode); break; } } return f.XsltInvokeEarlyBound(name, scrFunc.Method, scrFunc.XmlReturnType, args); }
/// <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)); }
/// <summary> /// Generate code for for QilNodeType.XsltInvokeEarlyBound. /// </summary> protected override QilNode VisitXsltInvokeEarlyBound(QilInvokeEarlyBound ndInvoke) { QilName ndName = ndInvoke.Name; XmlExtensionFunction extFunc; Type clrTypeRetSrc, clrTypeRetDst; // Retrieve metadata from the extension function extFunc = new XmlExtensionFunction(ndName.LocalName, ndName.NamespaceUri, ndInvoke.ClrMethod); clrTypeRetSrc = extFunc.ClrReturnType; clrTypeRetDst = GetStorageType(ndInvoke); // Prepare to call runtime.ChangeTypeXsltResult if (clrTypeRetSrc != clrTypeRetDst && !ndInvoke.XmlType.IsEmpty) { _helper.LoadQueryRuntime(); _helper.LoadInteger(_helper.StaticData.DeclareXmlType(ndInvoke.XmlType)); } // If this is not a static method, then get the instance object if (!extFunc.Method.IsStatic) { // Special-case the XsltLibrary object if (ndName.NamespaceUri.Length == 0) _helper.LoadXsltLibrary(); else _helper.CallGetEarlyBoundObject(_helper.StaticData.DeclareEarlyBound(ndName.NamespaceUri, extFunc.Method.DeclaringType), extFunc.Method.DeclaringType); } // Generate code to push each Invoke argument onto the stack for (int iArg = 0; iArg < ndInvoke.Arguments.Count; iArg++) { QilNode ndActualArg; XmlQueryType xmlTypeFormalArg; Type clrTypeActualArg, clrTypeFormalArg; ndActualArg = ndInvoke.Arguments[iArg]; // Infer Xml type and Clr type of formal argument xmlTypeFormalArg = extFunc.GetXmlArgumentType(iArg); clrTypeFormalArg = extFunc.GetClrArgumentType(iArg); Debug.Assert(ndActualArg.XmlType.IsSubtypeOf(xmlTypeFormalArg), "Xml type of actual arg must be a subtype of the Xml type of the formal arg"); // Use different conversion rules for internal Xslt libraries. If the actual argument is // stored using Clr type T, then library must use type T, XPathItem, IList<T>, or IList<XPathItem>. // If the actual argument is stored using Clr type IList<T>, then library must use type // IList<T> or IList<XPathItem>. This is to ensure that there will not be unnecessary // conversions that take place when calling into an internal library. if (ndName.NamespaceUri.Length == 0) { Type itemType = GetItemStorageType(ndActualArg); if (clrTypeFormalArg == XmlILMethods.StorageMethods[itemType].IListType) { // Formal type is IList<T> NestedVisitEnsureStack(ndActualArg, itemType, true); } else if (clrTypeFormalArg == XmlILMethods.StorageMethods[typeof(XPathItem)].IListType) { // Formal type is IList<XPathItem> NestedVisitEnsureStack(ndActualArg, typeof(XPathItem), true); } else if ((ndActualArg.XmlType.IsSingleton && clrTypeFormalArg == itemType) || ndActualArg.XmlType.TypeCode == XmlTypeCode.None) { // Formal type is T NestedVisitEnsureStack(ndActualArg, clrTypeFormalArg, false); } else if (ndActualArg.XmlType.IsSingleton && clrTypeFormalArg == typeof(XPathItem)) { // Formal type is XPathItem NestedVisitEnsureStack(ndActualArg, typeof(XPathItem), false); } else Debug.Fail("Internal Xslt library may not use parameters of type " + clrTypeFormalArg); } else { // There is an implicit upcast to the Xml type of the formal argument. This can change the Clr storage type. clrTypeActualArg = GetStorageType(xmlTypeFormalArg); // If the formal Clr type is typeof(object) or if it is not a supertype of the actual Clr type, then call ChangeTypeXsltArgument if (xmlTypeFormalArg.TypeCode == XmlTypeCode.Item || !clrTypeFormalArg.IsAssignableFrom(clrTypeActualArg)) { // (clrTypeFormalArg) runtime.ChangeTypeXsltArgument(xmlTypeFormalArg, (object) value, clrTypeFormalArg); _helper.LoadQueryRuntime(); _helper.LoadInteger(_helper.StaticData.DeclareXmlType(xmlTypeFormalArg)); NestedVisitEnsureStack(ndActualArg, GetItemStorageType(xmlTypeFormalArg), !xmlTypeFormalArg.IsSingleton); _helper.TreatAs(clrTypeActualArg, typeof(object)); _helper.LoadType(clrTypeFormalArg); _helper.Call(XmlILMethods.ChangeTypeXsltArg); _helper.TreatAs(typeof(object), clrTypeFormalArg); } else { NestedVisitEnsureStack(ndActualArg, GetItemStorageType(xmlTypeFormalArg), !xmlTypeFormalArg.IsSingleton); } } } // Invoke the target method _helper.Call(extFunc.Method); // Return value is on the stack; convert it to canonical ILGen storage type if (ndInvoke.XmlType.IsEmpty) { _helper.Emit(OpCodes.Ldsfld, XmlILMethods.StorageMethods[typeof(XPathItem)].SeqEmpty); } else if (clrTypeRetSrc != clrTypeRetDst) { // (T) runtime.ChangeTypeXsltResult(idxType, (object) value); _helper.TreatAs(clrTypeRetSrc, typeof(object)); _helper.Call(XmlILMethods.ChangeTypeXsltResult); _helper.TreatAs(typeof(object), clrTypeRetDst); } else if (ndName.NamespaceUri.Length != 0 && !clrTypeRetSrc.GetTypeInfo().IsValueType) { // Check for null if a user-defined extension function returns a reference type Label lblSkip = _helper.DefineLabel(); _helper.Emit(OpCodes.Dup); _helper.Emit(OpCodes.Brtrue, lblSkip); _helper.LoadQueryRuntime(); _helper.Emit(OpCodes.Ldstr, SR.Xslt_ItemNull); _helper.Call(XmlILMethods.ThrowException); _helper.MarkLabel(lblSkip); } _iterCurr.Storage = StorageDescriptor.Stack(GetItemStorageType(ndInvoke), !ndInvoke.XmlType.IsSingleton); return ndInvoke; }