/// <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));
}