2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / System.XML / System.Xml.Xsl / XslTransform.cs
index f910e7596e3951c5a0e96e9847c5678f3826e687..1aead131cd88827b24322efa8e3f17af48c56ca1 100644 (file)
@@ -1,52 +1,70 @@
-// System.Xml.Xsl.XslTransform\r
+// UnmanagedXslTransform\r
 //\r
 // Authors:\r
 //     Tim Coleman <tim@timcoleman.com>\r
 //     Gonzalo Paniagua Javier (gonzalo@ximian.com)\r
+//     Ben Maurer (bmaurer@users.sourceforge.net)\r
 //\r
 // (C) Copyright 2002 Tim Coleman\r
 // (c) 2003 Ximian Inc. (http://www.ximian.com)\r
+// (C) Ben Maurer 2003\r
 //\r
-\r
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+\r
+// DO NOT MOVE THIS FILE. WE WANT HISTORY\r
 using System;\r
-using System.Xml.XPath;\r
+using System.Collections;\r
 using System.IO;\r
+using System.Security.Policy;\r
 using System.Text;\r
 using System.Runtime.InteropServices;\r
+using System.Xml.XPath;\r
 \r
 using BF = System.Reflection.BindingFlags;\r
 \r
 namespace System.Xml.Xsl\r
 {\r
-       public unsafe sealed class XslTransform\r
+       internal unsafe sealed class UnmanagedXslTransform : XslTransformImpl\r
        {\r
 \r
                #region Fields\r
-\r
-               XmlResolver xmlResolver;\r
+               \r
                IntPtr stylesheet;\r
+               Hashtable extensionObjectCache = new Hashtable();\r
 \r
                #endregion\r
 \r
                #region Constructors\r
-               public XslTransform ()\r
+               public UnmanagedXslTransform ()\r
                {\r
                        stylesheet = IntPtr.Zero;\r
                }\r
 \r
                #endregion\r
 \r
-               #region Properties\r
-\r
-               public XmlResolver XmlResolver {\r
-                       set { xmlResolver = value; }\r
-               }\r
-\r
-               #endregion\r
-\r
                #region Methods\r
 \r
-               ~XslTransform ()\r
+               ~UnmanagedXslTransform ()\r
                {\r
                        FreeStylesheetIfNeeded ();\r
                }\r
@@ -58,47 +76,17 @@ namespace System.Xml.Xsl
                                stylesheet = IntPtr.Zero;\r
                        }\r
                }\r
-               \r
-               // Loads the XSLT stylesheet contained in the IXPathNavigable.\r
-               public void Load (IXPathNavigable stylesheet)\r
-               {\r
-                       Load (stylesheet.CreateNavigator ());\r
-               }\r
 \r
-               // Loads the XSLT stylesheet specified by a URL.\r
-               public void Load (string url)\r
+               public override void Load (string url, XmlResolver resolver)\r
                {\r
-                       if (url == null)\r
-                               throw new ArgumentNullException ("url");\r
-\r
                        FreeStylesheetIfNeeded ();\r
                        stylesheet = xsltParseStylesheetFile (url);\r
                        Cleanup ();\r
                        if (stylesheet == IntPtr.Zero)\r
                                throw new XmlException ("Error creating stylesheet");\r
                }\r
-\r
-               static IntPtr GetStylesheetFromString (string xml)\r
-               {\r
-                       IntPtr result = IntPtr.Zero;\r
-\r
-                       IntPtr xmlDoc = xmlParseDoc (xml);\r
-\r
-                       if (xmlDoc == IntPtr.Zero) {\r
-                               Cleanup ();\r
-                               throw new XmlException ("Error parsing stylesheet");\r
-                       }\r
-                               \r
-                       result = xsltParseStylesheetDoc (xmlDoc);\r
-                       Cleanup ();\r
-                       if (result == IntPtr.Zero)\r
-                               throw new XmlException ("Error creating stylesheet");\r
-\r
-                       return result;\r
-               }\r
-\r
-               // Loads the XSLT stylesheet contained in the XmlReader\r
-               public void Load (XmlReader stylesheet)\r
+               \r
+               public override void Load (XmlReader stylesheet, XmlResolver resolver, Evidence evidence)\r
                {\r
                        FreeStylesheetIfNeeded ();\r
                        // Create a document for the stylesheet\r
@@ -116,8 +104,7 @@ namespace System.Xml.Xsl
                                throw new XmlException ("Error creating stylesheet");\r
                }\r
 \r
-               // Loads the XSLT stylesheet contained in the XPathNavigator\r
-               public void Load (XPathNavigator stylesheet)\r
+               public override void Load (XPathNavigator stylesheet, XmlResolver resolver, Evidence evidence)\r
                {\r
                        FreeStylesheetIfNeeded ();\r
                        StringWriter sr = new UTF8StringWriter ();\r
@@ -127,79 +114,27 @@ namespace System.Xml.Xsl
                        if (this.stylesheet == IntPtr.Zero)\r
                                throw new XmlException ("Error creating stylesheet");\r
                }\r
-\r
-               [MonoTODO("use the resolver")]\r
-               // Loads the XSLT stylesheet contained in the IXPathNavigable.\r
-               public void Load (IXPathNavigable stylesheet, XmlResolver resolver)\r
-               {\r
-                       Load (stylesheet);\r
-               }\r
-\r
-               [MonoTODO("use the resolver")]\r
-               // Loads the XSLT stylesheet specified by a URL.\r
-               public void Load (string url, XmlResolver resolver)\r
-               {\r
-                       Load (url);\r
-               }\r
-\r
-               [MonoTODO("use the resolver")]\r
-               // Loads the XSLT stylesheet contained in the XmlReader\r
-               public void Load (XmlReader stylesheet, XmlResolver resolver)\r
-               {\r
-                       Load (stylesheet);\r
-               }\r
-\r
-               [MonoTODO("use the resolver")]\r
-               // Loads the XSLT stylesheet contained in the XPathNavigator\r
-               public void Load (XPathNavigator stylesheet, XmlResolver resolver)\r
-               {\r
-                       Load (stylesheet);\r
-               }\r
-\r
-               // Transforms the XML data in the IXPathNavigable using\r
-               // the specified args and outputs the result to an XmlReader.\r
-               public XmlReader Transform (IXPathNavigable input, XsltArgumentList args)\r
-               {\r
-                       if (input == null)\r
-                               throw new ArgumentNullException ("input");\r
-\r
-                       return Transform (input.CreateNavigator (), args);\r
-               }\r
-\r
-               // Transforms the XML data in the input file and outputs\r
-               // the result to an output file.\r
-               public void Transform (string inputfile, string outputfile)\r
+               \r
+               static IntPtr GetStylesheetFromString (string xml)\r
                {\r
-                       IntPtr xmlDocument = IntPtr.Zero;\r
-                       IntPtr resultDocument = IntPtr.Zero;\r
-\r
-                       try {\r
-                               xmlDocument = xmlParseFile (inputfile);\r
-                               if (xmlDocument == IntPtr.Zero)\r
-                                       throw new XmlException ("Error parsing input file");\r
-\r
-                               resultDocument = ApplyStylesheet (xmlDocument, null, null);\r
-\r
-                               /*\r
-                               * If I do this, the <?xml version=... is always present *\r
-                               if (-1 == xsltSaveResultToFilename (outputfile, resultDocument, stylesheet, 0))\r
-                                       throw new XmlException ("Error xsltSaveResultToFilename");\r
-                               */\r
-                               StreamWriter writer = new StreamWriter (File.OpenWrite (outputfile));\r
-                               writer.Write (GetStringFromDocument (resultDocument));\r
-                               writer.Close ();\r
-                       } finally {\r
-                               if (xmlDocument != IntPtr.Zero)\r
-                                       xmlFreeDoc (xmlDocument);\r
+                       IntPtr result = IntPtr.Zero;\r
 \r
-                               if (resultDocument != IntPtr.Zero)\r
-                                       xmlFreeDoc (resultDocument);\r
+                       IntPtr xmlDoc = xmlParseDoc (xml);\r
 \r
+                       if (xmlDoc == IntPtr.Zero) {\r
                                Cleanup ();\r
+                               throw new XmlException ("Error parsing stylesheet");\r
                        }\r
+                               \r
+                       result = xsltParseStylesheetDoc (xmlDoc);\r
+                       Cleanup ();\r
+                       if (result == IntPtr.Zero)\r
+                               throw new XmlException ("Error creating stylesheet");\r
+\r
+                       return result;\r
                }\r
 \r
-               IntPtr ApplyStylesheet (IntPtr doc, string[] argArr, System.Collections.Hashtable extobjects)\r
+               IntPtr ApplyStylesheet (IntPtr doc, string[] argArr, Hashtable extobjects)\r
                {\r
                        if (stylesheet == IntPtr.Zero)\r
                                throw new XmlException ("No style sheet!");\r
@@ -220,35 +155,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
-                                               System.Collections.Hashtable alreadyadded = new System.Collections.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
@@ -266,36 +223,31 @@ namespace System.Xml.Xsl
 \r
                static void Cleanup ()\r
                {\r
-                       xsltCleanupGlobals ();\r
-                       xmlCleanupParser ();\r
+                       //xsltCleanupGlobals ();\r
+                       //xmlCleanupParser ();\r
                }\r
 \r
-               static string GetStringFromDocument (IntPtr doc)\r
+               static string GetStringFromDocument (IntPtr doc, IntPtr stylesheet)\r
                {\r
                        IntPtr mem = IntPtr.Zero;\r
                        int size = 0;\r
-                       xmlDocDumpMemory (doc, ref mem, ref size);\r
-                       if (mem == IntPtr.Zero)\r
-                               throw new XmlException ("Error dumping document");\r
+\r
+                       int res = xsltSaveResultToString (ref mem, ref size, doc,\r
+                                                                                         stylesheet);\r
+                       if (res == -1)\r
+                               throw new XmlException ("xsltSaveResultToString () failed.");\r
 \r
                        string docStr = Marshal.PtrToStringAnsi (mem, size);\r
-                       // FIXME: Using xmlFree segfaults :-???\r
-                       //xmlFree (mem);\r
                        Marshal.FreeHGlobal (mem);\r
-                       //\r
-\r
-                       // Get rid of the <?xml...\r
-                       // FIXME: any other (faster) way that works?\r
-                       StringReader result = new StringReader (docStr);\r
-                       result.ReadLine (); // we want the semantics of line ending used here\r
-                       //\r
-                       return result.ReadToEnd ();\r
+                       return docStr;\r
                }\r
 \r
-               string ApplyStylesheetAndGetString (IntPtr doc, string[] argArr, System.Collections.Hashtable extobjects)\r
+               string ApplyStylesheetAndGetString (IntPtr doc, string[] argArr, Hashtable extobjects)\r
                {\r
-                       IntPtr xmlOutput = ApplyStylesheet (doc, argArr, extobjects);\r
-                       string strOutput = GetStringFromDocument (xmlOutput);\r
+                       IntPtr xmlOutput = ApplyStylesheet (doc,\r
+                               argArr == null ? new string [0] : argArr, \r
+                               extobjects == null ? new Hashtable () : extobjects);\r
+                       string strOutput = GetStringFromDocument (xmlOutput, stylesheet);\r
                        xmlFreeDoc (xmlOutput);\r
 \r
                        return strOutput;\r
@@ -312,76 +264,7 @@ namespace System.Xml.Xsl
                        return xmlInput;\r
                }\r
 \r
-               [MonoTODO("Node Set and Node Fragment Parameters and Extension Objects")]\r
-               // Transforms the XML data in the XPathNavigator using\r
-               // the specified args and outputs the result to an XmlReader.\r
-               public XmlReader Transform (XPathNavigator input, XsltArgumentList args)\r
-               {\r
-                       IntPtr xmlInput = GetDocumentFromNavigator (input);\r
-                       string[] argArr = null;\r
-                       if (args != null) {\r
-                               argArr = new string[args.parameters.Count * 2 + 1];\r
-                               int index = 0;\r
-                               foreach (object key in args.parameters.Keys) {\r
-                                       argArr [index++] = key.ToString();\r
-                                       object value = args.parameters [key];\r
-                                       if (value is Boolean)\r
-                                               argArr [index++] = XmlConvert.ToString((bool) value); // FIXME: How to encode it for libxslt?\r
-                                       else if (value is Double)\r
-                                               argArr [index++] = XmlConvert.ToString((double) value); // FIXME: How to encode infinity's and Nan?\r
-                                       else\r
-                                               argArr [index++] = "'" + value.ToString() + "'"; // FIXME: How to encode "'"?\r
-                               }\r
-                               argArr[index] = null;\r
-                       }\r
-                       string xslOutputString = ApplyStylesheetAndGetString (xmlInput, argArr, args.extensionObjects);\r
-                       xmlFreeDoc (xmlInput);\r
-                       Cleanup ();\r
-\r
-                       return new XmlTextReader (new StringReader (xslOutputString));\r
-               }\r
-\r
-               // Transforms the XML data in the IXPathNavigable using\r
-               // the specified args and outputs the result to a Stream.\r
-               public void Transform (IXPathNavigable input, XsltArgumentList args, Stream output)\r
-               {\r
-                       if (input == null)\r
-                               throw new ArgumentNullException ("input");\r
-\r
-                       Transform (input.CreateNavigator (), args, new StreamWriter (output));\r
-               }\r
-\r
-               // Transforms the XML data in the IXPathNavigable using\r
-               // the specified args and outputs the result to a TextWriter.\r
-               public void Transform (IXPathNavigable input, XsltArgumentList args, TextWriter output)\r
-               {\r
-                       if (input == null)\r
-                               throw new ArgumentNullException ("input");\r
-\r
-                       Transform (input.CreateNavigator (), args, output);\r
-               }\r
-\r
-               // Transforms the XML data in the IXPathNavigable using\r
-               // the specified args and outputs the result to an XmlWriter.\r
-               public void Transform (IXPathNavigable input, XsltArgumentList args, XmlWriter output)\r
-               {\r
-                       if (input == null)\r
-                               throw new ArgumentNullException ("input");\r
-\r
-                       Transform (input.CreateNavigator (), args, output);\r
-               }\r
-\r
-               // Transforms the XML data in the XPathNavigator using\r
-               // the specified args and outputs the result to a Stream.\r
-               public void Transform (XPathNavigator input, XsltArgumentList args, Stream output)\r
-               {\r
-                       Transform (input, args, new StreamWriter (output));\r
-               }\r
-\r
-               // Transforms the XML data in the XPathNavigator using\r
-               // the specified args and outputs the result to a TextWriter.\r
-               [MonoTODO("Node Set and Node Fragment Parameters and Extension Objects")]\r
-               public void Transform (XPathNavigator input, XsltArgumentList args, TextWriter output)\r
+               public override void Transform (XPathNavigator input, XsltArgumentList args, XmlWriter output, XmlResolver resolver)\r
                {\r
                        if (input == null)\r
                                throw new ArgumentNullException ("input");\r
@@ -389,9 +272,13 @@ namespace System.Xml.Xsl
                        if (output == null)\r
                                throw new ArgumentNullException ("output");\r
 \r
+                       StringWriter writer = new UTF8StringWriter ();\r
+                       \r
                        IntPtr inputDoc = GetDocumentFromNavigator (input);\r
                        string[] argArr = null;\r
+                       Hashtable extensionObjects = null;\r
                         if (args != null) {\r
+                               extensionObjects = args.extensionObjects;\r
                                argArr = new string[args.parameters.Count * 2 + 1];\r
                                int index = 0;\r
                                foreach (object key in args.parameters.Keys) {\r
@@ -406,23 +293,47 @@ namespace System.Xml.Xsl
                                }\r
                                argArr[index] = null;\r
                        }\r
-                       string transform = ApplyStylesheetAndGetString (inputDoc, argArr, args.extensionObjects);\r
+                       string transform = ApplyStylesheetAndGetString (inputDoc, argArr, extensionObjects);\r
                        xmlFreeDoc (inputDoc);\r
                        Cleanup ();\r
-                       output.Write (transform);\r
+                       writer.Write (transform);\r
+                       writer.Flush ();\r
+                       \r
+                       output.WriteRaw (writer.GetStringBuilder ().ToString ());\r
                        output.Flush ();\r
                }\r
+               public override void Transform (XPathNavigator input, XsltArgumentList args, TextWriter output, XmlResolver resolver) \r
+               {\r
+                       Transform(input, args, new XmlTextWriter(output), resolver);\r
+               }\r
 \r
-               // Transforms the XML data in the XPathNavigator using\r
-               // the specified args and outputs the result to an XmlWriter.\r
-               public void Transform (XPathNavigator input, XsltArgumentList args, XmlWriter output)\r
+               public override void Transform(string inputfile, string outputfile, XmlResolver resolver)\r
                {\r
-                       StringWriter writer = new UTF8StringWriter ();\r
-                       Transform (input, args, writer);\r
-                       output.WriteRaw (writer.GetStringBuilder ().ToString ());\r
-                       output.Flush ();\r
+                       IntPtr xmlDocument = IntPtr.Zero;\r
+                       IntPtr resultDocument = IntPtr.Zero;\r
+\r
+                       try {\r
+                               xmlDocument = xmlParseFile (inputfile);\r
+                               if (xmlDocument == IntPtr.Zero)\r
+                                       throw new XmlException ("Error parsing input file");\r
+\r
+                               resultDocument = ApplyStylesheet (xmlDocument, null, null);\r
+\r
+                               if (-1 == xsltSaveResultToFilename (outputfile, resultDocument, stylesheet, 0))\r
+                                       throw new XmlException ("Error in xsltSaveResultToFilename");\r
+                       } finally {\r
+                               if (xmlDocument != IntPtr.Zero)\r
+                                       xmlFreeDoc (xmlDocument);\r
+\r
+                               if (resultDocument != IntPtr.Zero)\r
+                                       xmlFreeDoc (resultDocument);\r
+\r
+                               Cleanup ();\r
+                       }\r
                }\r
 \r
+\r
+\r
                static void Save (XmlReader rdr, TextWriter baseWriter)\r
                {\r
                        XmlTextWriter writer = new XmlTextWriter (baseWriter);\r
@@ -488,6 +399,14 @@ namespace System.Xml.Xsl
                {\r
                        WriteCurrentNode (navigator, writer);\r
 \r
+                       if (navigator.MoveToFirstNamespace (XPathNamespaceScope.Local)) {\r
+                               do {\r
+                                       WriteCurrentNode (navigator, writer);\r
+                               } while (navigator.MoveToNextNamespace (XPathNamespaceScope.Local));\r
+\r
+                               navigator.MoveToParent ();\r
+                       }\r
+\r
                        if (navigator.MoveToFirstAttribute ()) {\r
                                do {\r
                                        WriteCurrentNode (navigator, writer);\r
@@ -516,6 +435,15 @@ namespace System.Xml.Xsl
                        case XPathNodeType.Root:\r
                                writer.WriteStartDocument ();\r
                                break;\r
+                       case XPathNodeType.Namespace:\r
+                               if (navigator.Name == String.Empty)\r
+                                       writer.WriteAttributeString ("xmlns", navigator.Value);\r
+                               else\r
+                                       writer.WriteAttributeString ("xmlns",\r
+                                               navigator.Name,\r
+                                               "http://www.w3.org/2000/xmlns/",\r
+                                               navigator.Value);\r
+                               break;\r
                        case XPathNodeType.Attribute:\r
                                writer.WriteAttributeString (navigator.Name, navigator.Value);\r
                                break;\r
@@ -547,14 +475,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
@@ -565,7 +500,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
@@ -584,19 +519,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
@@ -612,7 +547,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
@@ -629,6 +564,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
@@ -656,6 +593,10 @@ namespace System.Xml.Xsl
                [DllImport ("xslt")]\r
                static extern IntPtr xsltApplyStylesheet (IntPtr stylePtr, IntPtr DocPtr, string[] argPtr);\r
 \r
+               [DllImport ("xslt")]\r
+               static extern int xsltSaveResultToString (ref IntPtr stringPtr, ref int stringLen,\r
+                                                                                                 IntPtr docPtr, IntPtr stylePtr);\r
+\r
                [DllImport ("xslt")]\r
                static extern int xsltSaveResultToFilename (string URI, IntPtr doc, IntPtr styleSheet, int compression);\r
 \r