/// <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 = (this.argList != null) ? this.argList.GetExtensionObject(namespaceUri) : null; if (instance == null) throw new XslTransformException(Res.XmlIl_UnknownExtObj, namespaceUri); // Bind to a method on the instance object if (this.extFuncsLate == null) this.extFuncsLate = new XmlExtensionFunctionTable(); // Bind to the instance, looking for a matching method (throws if no matching method) XmlExtensionFunction extFunc = this.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] = this.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>) this.runtime.ChangeTypeXsltResult(XmlQueryTypeFactory.ItemS, objRet); }