2003-06-01 Joshua Tauberer <tauberer@for.net>
authorJoshua Tauberer <joshua@mono-cvs.ximian.com>
Sun, 1 Jun 2003 15:39:08 +0000 (15:39 -0000)
committerJoshua Tauberer <joshua@mono-cvs.ximian.com>
Sun, 1 Jun 2003 15:39:08 +0000 (15:39 -0000)
        * XslTransform.cs: Cache extension object delegates
        between calls to Transform.

svn path=/trunk/mcs/; revision=15051

mcs/class/System.XML/System.Xml.Xsl/ChangeLog
mcs/class/System.XML/System.Xml.Xsl/XslTransform.cs

index 9549ae446ab9e7e0a9bb7aadbe561ef20fa6cc08..bcbb651e5cb551e911ce020541c1bcf392d4c392 100644 (file)
@@ -1,3 +1,8 @@
+2003-06-01  Joshua Tauberer <tauberer@for.net>
+
+       * XslTransform.cs: Cache extension object delegates
+       between calls to Transform.
+
 2003-05-28  Gonzalo Paniagua Javier <gonzalo@ximian.com>
 
        * XslTransform.cs: fixed NullReferenceExceptions after the last
index 567d3802bc80736f116d6796ee97de4cd49789d4..1de4718ad4faee5feeb16c1523c9f026e8eb4210 100644 (file)
@@ -26,6 +26,7 @@ namespace System.Xml.Xsl
 \r
                XmlResolver xmlResolver;\r
                IntPtr stylesheet;\r
+               Hashtable extensionObjectCache = new Hashtable();\r
 \r
                #endregion\r
 \r
@@ -221,35 +222,57 @@ namespace System.Xml.Xsl
                                        foreach (string ns in extobjects.Keys) {\r
                                                object ext = extobjects[ns];\r
 \r
-                                               System.Type type;\r
-                                               System.Collections.IEnumerable methods;\r
+                                               if (extensionObjectCache.ContainsKey(ext)) {\r
+                                                       foreach (ExtensionFunctionHolder ef in (ArrayList)extensionObjectCache[ext]) {\r
+                                                               int ret = xsltRegisterExtFunction(context, ef.name, ef.ns, ef.func);\r
+                                                               if (ret != 0) throw new XmlException("Could not reregister extension function " + ef.name + " in " + ef.ns);\r
+                                                       }\r
 \r
-                                               // As an added bonus, if the extension object is a UseStaticMethods object\r
-                                               // (defined below), then add the static methods of the specified type.\r
-                                               if (ext is UseStaticMethods) {\r
-                                                       type = ((UseStaticMethods)ext).Type;\r
-                                                       methods = type.GetMethods(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);\r
-                                                       ext = null;\r
                                                } else {\r
-                                                       type = ext.GetType();\r
-                                                       methods = type.GetMethods();\r
-                                               }\r
+                                                       object extsrc;\r
+       \r
+                                                       System.Type type;\r
+                                                       System.Collections.IEnumerable methods;\r
+       \r
+                                                       // As an added bonus, if the extension object is a UseStaticMethods object\r
+                                                       // (defined below), then add the static methods of the specified type.\r
+                                                       if (ext is UseStaticMethods) {\r
+                                                               type = ((UseStaticMethods)ext).Type;\r
+                                                               methods = type.GetMethods(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);\r
+                                                               extsrc = null;\r
+                                                       } else {\r
+                                                               extsrc = ext;\r
+                                                               type = ext.GetType();\r
+                                                               methods = type.GetMethods();\r
+                                                       }\r
+\r
+                                                       ArrayList functionstocache = new ArrayList();\r
+       \r
+                                                       Hashtable alreadyadded = new Hashtable ();\r
+                                                       foreach (System.Reflection.MethodInfo mi in methods) {\r
+                                                               if (alreadyadded.ContainsKey(mi.Name)) continue; // don't add twice\r
+                                                               alreadyadded[mi.Name] = 1;\r
 \r
-                                               Hashtable alreadyadded = new Hashtable ();\r
-                                               foreach (System.Reflection.MethodInfo mi in methods) {\r
-                                                       if (alreadyadded.ContainsKey(mi.Name)) continue; // don't add twice\r
-                                                       alreadyadded[mi.Name] = 1;\r
+                                                               // Simple extension function delegate\r
+                                                               ExtensionFunction func = new ExtensionFunction(new ReflectedExtensionFunction(type, extsrc, mi.Name).Function);\r
+       \r
+                                                               // Delegate for libxslt library call\r
+                                                               libxsltXPathFunction libfunc = new libxsltXPathFunction(new ExtensionFunctionWrapper(func).Function);\r
+               \r
+                                                               int ret = xsltRegisterExtFunction(context, mi.Name, ns, libfunc);\r
+                                                               if (ret != 0) throw new XmlException("Could not register extension function " + mi.DeclaringType.FullName + "." + mi.Name + " in " + ns);\r
 \r
-                                                       // Simple extension function delegate\r
-                                                       ExtensionFunction func = new ExtensionFunction(new ReflectedExtensionFunction(type, ext, mi.Name).Function);\r
+                                                               ExtensionFunctionHolder efh;\r
+                                                               efh.name = mi.Name;\r
+                                                               efh.ns = ns;\r
+                                                               efh.func = libfunc;\r
+                                                               functionstocache.Add(efh);\r
+                                                       }\r
+\r
+                                                       extensionObjectCache[ext] = functionstocache;\r
 \r
-                                                       // Delegate for libxslt library call\r
-                                                       libxsltXPathFunction libfunc = new libxsltXPathFunction(new ExtensionFunctionWrapper(func).Function);\r
-       \r
-                                                       int ret = xsltRegisterExtFunction(context, mi.Name, ns, libfunc);\r
-                                                       if (ret != 0) throw new XmlException("Could not register extension function " + mi.DeclaringType.FullName + "." + mi.Name + " in " + ns);\r
                                                }\r
-                                       \r
+                                               \r
                                        }\r
        \r
                                        result = xsltApplyStylesheetUser(stylesheet, doc, argArr, null, IntPtr.Zero, context);\r
@@ -552,14 +575,21 @@ namespace System.Xml.Xsl
 \r
                internal delegate object ExtensionFunction(object[] args);\r
 \r
+               private struct ExtensionFunctionHolder {\r
+                       public libxsltXPathFunction func;\r
+                       public string ns, name;\r
+               }\r
+\r
                // Wraps an ExtensionFunction into a function that is callable from the libxslt library.\r
                private unsafe class ExtensionFunctionWrapper {\r
-                       ExtensionFunction func;\r
+                       private readonly ExtensionFunction func;\r
 \r
-                       public ExtensionFunctionWrapper(ExtensionFunction func) { this.func = func; }\r
-                       \r
-                       public unsafe void Function(IntPtr xpath_ctxt, int nargs) {\r
+                       public ExtensionFunctionWrapper(ExtensionFunction func) {\r
+                               if ((object)func == null) throw new ArgumentNullException("func");\r
+                               this.func = func;\r
+                       }\r
 \r
+                       public unsafe void Function(IntPtr xpath_ctxt, int nargs) {\r
                                // Convert XPath arguments into "managed" arguments\r
                                System.Collections.ArrayList args = new System.Collections.ArrayList();\r
                                for (int i = 0; i < nargs; i++) {\r
@@ -570,7 +600,7 @@ namespace System.Xml.Xsl
                                                args.Add( xmlXPathCastToNumber(aptr));\r
                                        else if (aptr->type == 4) // Strings\r
                                                args.Add( xmlXPathCastToString(aptr));\r
-                                       else if (aptr->type == 1) { // Node Sets ==> ArrayList of strings\r
+                                       else if (aptr->type == 1 && aptr->nodesetptr != null) { // Node Sets ==> ArrayList of strings\r
                                                System.Collections.ArrayList a = new System.Collections.ArrayList();\r
                                                for (int ni = 0; ni < aptr->nodesetptr->count; ni++) {\r
                                                        xpathobject *n = xmlXPathNewNodeSet(aptr->nodesetptr->nodes[ni]);\r
@@ -589,19 +619,19 @@ namespace System.Xml.Xsl
                                        xmlXPathFreeObject(aptr);\r
                                }\r
 \r
-                               // Call function\r
                                args.Reverse();\r
+\r
                                object ret = func(args.ToArray());\r
 \r
                                // Convert the result back to an XPath object\r
                                if (ret == null) // null => ""\r
                                        valuePush(xpath_ctxt, xmlXPathNewCString(""));\r
-                               else if (ret is Boolean) // Booleans\r
+                               else if (ret is bool) // Booleans\r
                                        valuePush(xpath_ctxt, xmlXPathNewBoolean((bool)ret ? 1 : 0));\r
                                else if (ret is int || ret is long || ret is double || ret is float || ret is decimal)\r
                                        // Numbers\r
                                        valuePush(xpath_ctxt, xmlXPathNewFloat((double)ret));\r
-                               else // Strings\r
+                               else // Everything else => String\r
                                        valuePush(xpath_ctxt, xmlXPathNewCString(ret.ToString()));\r
 \r
                        }\r
@@ -617,7 +647,7 @@ namespace System.Xml.Xsl
                        public ReflectedExtensionFunction(System.Type type, object src, string methodname) { this.type = type; this.src = src; this.methodname = methodname; }\r
                \r
                        public object Function(object[] args) {\r
-                               // Construct arg type array, stringified version in case of problem\r
+                               // Construct arg type array, and a stringified version in case of problem\r
                                System.Type[] argtypes = new System.Type[args.Length];\r
                                string argtypelist = null;\r
                                for (int i = 0; i < args.Length; i++) {\r
@@ -634,6 +664,8 @@ namespace System.Xml.Xsl
                                // No method?\r
                                if (mi == null) throw new XmlException("No applicable function for " + methodname + " takes (" + argtypelist + ")");\r
 \r
+                               if (!mi.IsStatic && src == null) throw new XmlException("Attempt to call static method without instantiated extension object.");\r
+\r
                                // Invoke\r
                                return mi.Invoke(src, args);\r
                        }\r