Table of bound extension functions. Once an extension function is bound and entered into the table, future bindings will be very fast. This table is not thread-safe.
Ejemplo n.º 1
0
        /// <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);
        }