-// 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
-// Author: Tim Coleman <tim@timcoleman.com>\r
// (C) Copyright 2002 Tim Coleman\r
+// (c) 2003 Ximian Inc. (http://www.ximian.com)\r
+// (C) Ben Maurer 2003\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 class XslTransform\r
+ internal unsafe sealed class UnmanagedXslTransform : XslTransformImpl\r
{\r
- #region Fields\r
\r
- XmlResolver xmlResolver;\r
+ #region Fields\r
+ \r
+ IntPtr stylesheet;\r
+ Hashtable extensionObjectCache = new Hashtable();\r
\r
#endregion\r
\r
#region Constructors\r
-\r
- [MonoTODO]\r
- public XslTransform ()\r
+ public UnmanagedXslTransform ()\r
{\r
- }\r
-\r
- #endregion\r
-\r
- #region Properties\r
-\r
- XmlResolver XmlResolver {\r
- set { xmlResolver = value; }\r
+ stylesheet = IntPtr.Zero;\r
}\r
\r
#endregion\r
\r
#region Methods\r
\r
- [MonoTODO]\r
- // Loads the XSLT stylesheet contained in the IXPathNavigable.\r
- public void Load (IXPathNavigable stylesheet)\r
+ ~UnmanagedXslTransform ()\r
{\r
+ FreeStylesheetIfNeeded ();\r
}\r
\r
- [MonoTODO]\r
- // Loads the XSLT stylesheet specified by a URL.\r
- public void Load (string url)\r
+ void FreeStylesheetIfNeeded ()\r
{\r
+ if (stylesheet != IntPtr.Zero) {\r
+ xsltFreeStylesheet (stylesheet);\r
+ stylesheet = IntPtr.Zero;\r
+ }\r
}\r
\r
- [MonoTODO]\r
- // Loads the XSLT stylesheet contained in the XmlReader\r
- public void Load (XmlReader stylesheet)\r
+ public override void Load (string url, XmlResolver resolver)\r
{\r
+ FreeStylesheetIfNeeded ();\r
+ stylesheet = xsltParseStylesheetFile (url);\r
+ Cleanup ();\r
+ if (stylesheet == IntPtr.Zero)\r
+ throw new XmlException ("Error creating stylesheet");\r
}\r
-\r
- [MonoTODO]\r
- // Loads the XSLT stylesheet contained in the XPathNavigator\r
- public void Load (XPathNavigator stylesheet)\r
+ \r
+ public override void Load (XmlReader stylesheet, XmlResolver resolver, Evidence evidence)\r
{\r
+ FreeStylesheetIfNeeded ();\r
+ // Create a document for the stylesheet\r
+ XmlDocument doc = new XmlDocument ();\r
+ doc.Load (stylesheet);\r
+ \r
+ // Store the XML in a StringBuilder\r
+ StringWriter sr = new UTF8StringWriter ();\r
+ XmlTextWriter writer = new XmlTextWriter (sr);\r
+ doc.Save (writer);\r
+\r
+ this.stylesheet = GetStylesheetFromString (sr.GetStringBuilder ().ToString ());\r
+ Cleanup ();\r
+ if (this.stylesheet == IntPtr.Zero)\r
+ throw new XmlException ("Error creating stylesheet");\r
}\r
\r
- [MonoTODO]\r
- // Loads the XSLT stylesheet contained in the IXPathNavigable.\r
- public void Load (IXPathNavigable stylesheet, XmlResolver resolver)\r
+ public override void Load (XPathNavigator stylesheet, XmlResolver resolver, Evidence evidence)\r
{\r
+ FreeStylesheetIfNeeded ();\r
+ StringWriter sr = new UTF8StringWriter ();\r
+ Save (stylesheet, sr);\r
+ this.stylesheet = GetStylesheetFromString (sr.GetStringBuilder ().ToString ());\r
+ Cleanup ();\r
+ if (this.stylesheet == IntPtr.Zero)\r
+ throw new XmlException ("Error creating stylesheet");\r
}\r
-\r
- [MonoTODO]\r
- // Loads the XSLT stylesheet specified by a URL.\r
- public void Load (string url, XmlResolver resolver)\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
- [MonoTODO]\r
- // Loads the XSLT stylesheet contained in the XmlReader\r
- public void Load (XmlReader stylesheet, XmlResolver resolver)\r
+ IntPtr ApplyStylesheet (IntPtr doc, string[] argArr, Hashtable extobjects)\r
{\r
+ if (stylesheet == IntPtr.Zero)\r
+ throw new XmlException ("No style sheet!");\r
+\r
+ IntPtr result;\r
+\r
+ if (extobjects == null || extobjects.Count == 0) {\r
+ // If there are no extension objects, use the simple (old) method.\r
+ result = xsltApplyStylesheet (stylesheet, doc, argArr);\r
+ } else {\r
+ // If there are extension objects, create a context and register the functions.\r
+\r
+ IntPtr context = xsltNewTransformContext(stylesheet, doc);\r
+\r
+ if (context == IntPtr.Zero) throw new XmlException("Error creating transformation context.");\r
+\r
+ try {\r
+ foreach (string ns in extobjects.Keys) {\r
+ object ext = extobjects[ns];\r
+\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
+ } else {\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
+ // 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
+ 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
+ }\r
+ \r
+ }\r
+ \r
+ result = xsltApplyStylesheetUser(stylesheet, doc, argArr, null, IntPtr.Zero, context);\r
+ } finally {\r
+ xsltFreeTransformContext(context);\r
+ }\r
+ }\r
+\r
+\r
+ if (result == IntPtr.Zero)\r
+ throw new XmlException ("Error applying style sheet");\r
+\r
+ return result;\r
}\r
\r
- [MonoTODO]\r
- // Loads the XSLT stylesheet contained in the XPathNavigator\r
- public void Load (XPathNavigator stylesheet, XmlResolver resolver)\r
+ static void Cleanup ()\r
{\r
+ //xsltCleanupGlobals ();\r
+ //xmlCleanupParser ();\r
}\r
\r
- [MonoTODO]\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
+ static string GetStringFromDocument (IntPtr doc, IntPtr stylesheet)\r
{\r
- return null;\r
+ IntPtr mem = IntPtr.Zero;\r
+ int size = 0;\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
+ Marshal.FreeHGlobal (mem);\r
+ return docStr;\r
}\r
\r
- [MonoTODO]\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
+ string ApplyStylesheetAndGetString (IntPtr doc, string[] argArr, Hashtable extobjects)\r
{\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
}\r
\r
- [MonoTODO]\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
+ IntPtr GetDocumentFromNavigator (XPathNavigator nav)\r
{\r
- return null;\r
+ StringWriter sr = new UTF8StringWriter ();\r
+ Save (nav, sr);\r
+ IntPtr xmlInput = xmlParseDoc (sr.GetStringBuilder ().ToString ());\r
+ if (xmlInput == IntPtr.Zero)\r
+ throw new XmlException ("Error getting XML from input");\r
+\r
+ return xmlInput;\r
}\r
\r
- [MonoTODO]\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
+ public override void Transform (XPathNavigator input, XsltArgumentList args, XmlWriter output, XmlResolver resolver)\r
+ {\r
+ if (input == null)\r
+ throw new ArgumentNullException ("input");\r
+\r
+ 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
+ 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 transform = ApplyStylesheetAndGetString (inputDoc, argArr, extensionObjects);\r
+ xmlFreeDoc (inputDoc);\r
+ Cleanup ();\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
- [MonoTODO]\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
+ public override void Transform(string inputfile, string outputfile, XmlResolver resolver)\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
+ 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
- [MonoTODO]\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
+\r
+ static void Save (XmlReader rdr, TextWriter baseWriter)\r
{\r
+ XmlTextWriter writer = new XmlTextWriter (baseWriter);\r
+ \r
+ while (rdr.Read ()) {\r
+ switch (rdr.NodeType) {\r
+ \r
+ case XmlNodeType.CDATA:\r
+ writer.WriteCData (rdr.Value);\r
+ break;\r
+ \r
+ case XmlNodeType.Comment:\r
+ writer.WriteComment (rdr.Value);\r
+ break;\r
+\r
+ case XmlNodeType.DocumentType:\r
+ writer.WriteDocType (rdr.Value, null, null, null);\r
+ break;\r
+\r
+ case XmlNodeType.Element:\r
+ writer.WriteStartElement (rdr.Name, rdr.Value);\r
+ \r
+ while (rdr.MoveToNextAttribute ())\r
+ writer.WriteAttributes (rdr, true);\r
+ break;\r
+ \r
+ case XmlNodeType.EndElement:\r
+ writer.WriteEndElement ();\r
+ break;\r
+\r
+ case XmlNodeType.ProcessingInstruction:\r
+ writer.WriteProcessingInstruction (rdr.Name, rdr.Value);\r
+ break;\r
+\r
+ case XmlNodeType.Text:\r
+ writer.WriteString (rdr.Value);\r
+ break;\r
+\r
+ case XmlNodeType.Whitespace:\r
+ writer.WriteWhitespace (rdr.Value);\r
+ break;\r
+\r
+ case XmlNodeType.XmlDeclaration:\r
+ writer.WriteStartDocument ();\r
+ break;\r
+ }\r
+ }\r
+\r
+ writer.Close ();\r
}\r
\r
- [MonoTODO]\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
+ static void Save (XPathNavigator navigator, TextWriter writer)\r
{\r
+ XmlTextWriter xmlWriter = new XmlTextWriter (writer);\r
+\r
+ WriteTree (navigator, xmlWriter);\r
+ xmlWriter.WriteEndDocument ();\r
+ xmlWriter.Flush ();\r
}\r
\r
- [MonoTODO]\r
- // Transforms the XML data in the XPathNavigator using\r
- // the specified args and outputs the result to a TextWriter.\r
- public void Transform (XPathNavigator input, XsltArgumentList args, TextWriter output)\r
+ // Walks the XPathNavigator tree recursively \r
+ static void WriteTree (XPathNavigator navigator, XmlTextWriter writer)\r
{\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
+ } while (navigator.MoveToNextAttribute ());\r
+\r
+ navigator.MoveToParent ();\r
+ }\r
+\r
+ if (navigator.MoveToFirstChild ()) {\r
+ do {\r
+ WriteTree (navigator, writer);\r
+ } while (navigator.MoveToNext ());\r
+\r
+ navigator.MoveToParent ();\r
+ if (navigator.NodeType != XPathNodeType.Root)\r
+ writer.WriteEndElement ();\r
+ } else if (navigator.NodeType == XPathNodeType.Element) {\r
+ writer.WriteEndElement ();\r
+ }\r
}\r
\r
- [MonoTODO]\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
+ // Format the output \r
+ static void WriteCurrentNode (XPathNavigator navigator, XmlTextWriter writer)\r
{\r
+ switch (navigator.NodeType) {\r
+ 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
+\r
+ case XPathNodeType.Comment:\r
+ writer.WriteComment (navigator.Value);\r
+ break;\r
+\r
+ case XPathNodeType.Element:\r
+ writer.WriteStartElement (navigator.Name);\r
+ break;\r
+ \r
+ case XPathNodeType.ProcessingInstruction:\r
+ writer.WriteProcessingInstruction (navigator.Name, navigator.Value);\r
+ break;\r
+\r
+ case XPathNodeType.Text:\r
+ writer.WriteString (navigator.Value);\r
+ break;\r
+\r
+ case XPathNodeType.SignificantWhitespace:\r
+ case XPathNodeType.Whitespace:\r
+ writer.WriteWhitespace (navigator.Value);\r
+ break;\r
+ }\r
+ }\r
+\r
+ // Extension Objects\r
+\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
+ private readonly ExtensionFunction func;\r
+\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
+ xpathobject* aptr = valuePop(xpath_ctxt);\r
+ if (aptr->type == 2) // Booleans\r
+ args.Add( xmlXPathCastToBoolean(aptr) == 0 ? false : true );\r
+ else if (aptr->type == 3) // Doubles\r
+ args.Add( xmlXPathCastToNumber(aptr));\r
+ else if (aptr->type == 4) // Strings\r
+ args.Add( xmlXPathCastToString(aptr));\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
+ valuePush(xpath_ctxt, n);\r
+ xmlXPathStringFunction(xpath_ctxt, 1);\r
+ a.Add(xmlXPathCastToString(valuePop(xpath_ctxt)));\r
+ xmlXPathFreeObject(n);\r
+ }\r
+ args.Add(a);\r
+ } else { // Anything else => string\r
+ valuePush(xpath_ctxt, aptr);\r
+ xmlXPathStringFunction(xpath_ctxt, 1);\r
+ args.Add(xmlXPathCastToString(valuePop(xpath_ctxt)));\r
+ }\r
+\r
+ xmlXPathFreeObject(aptr);\r
+ }\r
+\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 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 // Everything else => String\r
+ valuePush(xpath_ctxt, xmlXPathNewCString(ret.ToString()));\r
+\r
+ }\r
+ }\r
+\r
+ // Provides a delegate for calling a late-bound method of a type with a given name.\r
+ // Determines method based on types of arguments.\r
+ private class ReflectedExtensionFunction {\r
+ System.Type type;\r
+ object src;\r
+ string methodname;\r
+ \r
+ 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, 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
+ argtypes[i] = (args[i] == null ? typeof(object) : args[i].GetType() );\r
+\r
+ if (argtypelist != null) argtypelist += ", ";\r
+ argtypelist += argtypes[i].FullName;\r
+ }\r
+ if (argtypelist == null) argtypelist = "";\r
+\r
+ // Find the method\r
+ System.Reflection.MethodInfo mi = type.GetMethod(methodname, (src == null ? BF.Static : BF.Instance | BF.Static) | BF.Public, null, argtypes, null);\r
+\r
+ // 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
+ }\r
+\r
+ // Special Mono-specific class that allows static methods of a type to\r
+ // be bound without needing an instance of that type. Useful for\r
+ // registering System.Math functions, for example.\r
+ // Usage: args.AddExtensionObject( new XslTransform.UseStaticMethods(typeof(thetype)) );\r
+ public sealed class UseStaticMethods {\r
+ public readonly System.Type Type;\r
+ public UseStaticMethods(System.Type Type) { this.Type = Type; }\r
+ }\r
+\r
+ #endregion\r
+\r
+ #region Calls to external libraries\r
+ // libxslt\r
+ [DllImport ("xslt")]\r
+ static extern IntPtr xsltParseStylesheetFile (string filename);\r
+\r
+ [DllImport ("xslt")]\r
+ static extern IntPtr xsltParseStylesheetDoc (IntPtr docPtr);\r
+\r
+ [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
+ [DllImport ("xslt")]\r
+ static extern void xsltCleanupGlobals ();\r
+\r
+ [DllImport ("xslt")]\r
+ static extern void xsltFreeStylesheet (IntPtr cur);\r
+\r
+ // libxml2\r
+ [DllImport ("xml2")]\r
+ static extern IntPtr xmlNewDoc (string version);\r
+\r
+ [DllImport ("xml2")]\r
+ static extern int xmlSaveFile (string filename, IntPtr cur);\r
+\r
+ [DllImport ("xml2")]\r
+ static extern IntPtr xmlParseFile (string filename);\r
+\r
+ [DllImport ("xml2")]\r
+ static extern IntPtr xmlParseDoc (string document);\r
+\r
+ [DllImport ("xml2")]\r
+ static extern void xmlFreeDoc (IntPtr doc);\r
+\r
+ [DllImport ("xml2")]\r
+ static extern void xmlCleanupParser ();\r
+\r
+ [DllImport ("xml2")]\r
+ static extern void xmlDocDumpMemory (IntPtr doc, ref IntPtr mem, ref int size);\r
+\r
+ [DllImport ("xml2")]\r
+ static extern void xmlFree (IntPtr data);\r
+\r
+ // Functions and structures for extension objects\r
+\r
+ [DllImport ("xslt")]\r
+ static extern IntPtr xsltNewTransformContext (IntPtr style, IntPtr doc);\r
+\r
+ [DllImport ("xslt")]\r
+ static extern void xsltFreeTransformContext (IntPtr context);\r
+\r
+ [DllImport ("xslt")]\r
+ static extern IntPtr xsltApplyStylesheetUser (IntPtr stylePtr, IntPtr DocPtr, string[] argPtr, string output, IntPtr profile, IntPtr context);\r
+\r
+ [DllImport ("xslt")]\r
+ static extern int xsltRegisterExtFunction (IntPtr context, string name, string uri, libxsltXPathFunction function);\r
+\r
+ [DllImport ("xml2")]\r
+ unsafe static extern xpathobject* valuePop (IntPtr context);\r
+\r
+ [DllImport ("xml2")]\r
+ unsafe static extern void valuePush (IntPtr context, xpathobject* data);\r
+\r
+ [DllImport("xml2")]\r
+ unsafe static extern void xmlXPathFreeObject(xpathobject* obj);\r
+ \r
+ [DllImport("xml2")]\r
+ unsafe static extern xpathobject* xmlXPathNewCString(string str);\r
+\r
+ [DllImport("xml2")]\r
+ unsafe static extern xpathobject* xmlXPathNewFloat(double val);\r
+\r
+ [DllImport("xml2")]\r
+ unsafe static extern xpathobject* xmlXPathNewBoolean(int val);\r
+\r
+ [DllImport("xml2")]\r
+ unsafe static extern xpathobject* xmlXPathNewNodeSet(IntPtr nodeptr);\r
+\r
+ [DllImport("xml2")]\r
+ unsafe static extern int xmlXPathCastToBoolean(xpathobject* val);\r
+\r
+ [DllImport("xml2")]\r
+ unsafe static extern double xmlXPathCastToNumber(xpathobject* val);\r
+\r
+ [DllImport("xml2")]\r
+ unsafe static extern string xmlXPathCastToString(xpathobject* val);\r
+\r
+ [DllImport("xml2")]\r
+ static extern void xmlXPathStringFunction(IntPtr context, int nargs);\r
+\r
+ private delegate void libxsltXPathFunction(IntPtr xpath_ctxt, int nargs);\r
+\r
+ private struct xpathobject {\r
+ public int type;\r
+ public xmlnodelist* nodesetptr;\r
+ }\r
+ private struct xmlnodelist {\r
+ public int count;\r
+ public int allocated;\r
+ public IntPtr* nodes;\r
}\r
\r
#endregion\r
+\r
+ // This classes just makes the base class use 'encoding="utf-8"'\r
+ class UTF8StringWriter : StringWriter\r
+ {\r
+ static Encoding encoding = new UTF8Encoding (false);\r
+\r
+ public override Encoding Encoding {\r
+ get {\r
+ return encoding;\r
+ }\r
+ }\r
+ }\r
}\r
}\r