XslTransform.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794
  1. // System.Xml.Xsl.XslTransform
  2. //
  3. // Authors:
  4. // Tim Coleman <[email protected]>
  5. // Gonzalo Paniagua Javier ([email protected])
  6. //
  7. // (C) Copyright 2002 Tim Coleman
  8. // (c) 2003 Ximian Inc. (http://www.ximian.com)
  9. //
  10. using System;
  11. using System.Collections;
  12. using System.IO;
  13. using System.Text;
  14. using System.Runtime.InteropServices;
  15. using System.Xml.XPath;
  16. using BF = System.Reflection.BindingFlags;
  17. namespace System.Xml.Xsl
  18. {
  19. public unsafe sealed class XslTransform
  20. {
  21. #region Fields
  22. XmlResolver xmlResolver;
  23. IntPtr stylesheet;
  24. Hashtable extensionObjectCache = new Hashtable();
  25. #endregion
  26. #region Constructors
  27. public XslTransform ()
  28. {
  29. stylesheet = IntPtr.Zero;
  30. }
  31. #endregion
  32. #region Properties
  33. public XmlResolver XmlResolver {
  34. set { xmlResolver = value; }
  35. }
  36. #endregion
  37. #region Methods
  38. ~XslTransform ()
  39. {
  40. FreeStylesheetIfNeeded ();
  41. }
  42. void FreeStylesheetIfNeeded ()
  43. {
  44. if (stylesheet != IntPtr.Zero) {
  45. xsltFreeStylesheet (stylesheet);
  46. stylesheet = IntPtr.Zero;
  47. }
  48. }
  49. // Loads the XSLT stylesheet contained in the IXPathNavigable.
  50. public void Load (IXPathNavigable stylesheet)
  51. {
  52. Load (stylesheet.CreateNavigator ());
  53. }
  54. // Loads the XSLT stylesheet specified by a URL.
  55. public void Load (string url)
  56. {
  57. if (url == null)
  58. throw new ArgumentNullException ("url");
  59. FreeStylesheetIfNeeded ();
  60. stylesheet = xsltParseStylesheetFile (url);
  61. Cleanup ();
  62. if (stylesheet == IntPtr.Zero)
  63. throw new XmlException ("Error creating stylesheet");
  64. }
  65. static IntPtr GetStylesheetFromString (string xml)
  66. {
  67. IntPtr result = IntPtr.Zero;
  68. IntPtr xmlDoc = xmlParseDoc (xml);
  69. if (xmlDoc == IntPtr.Zero) {
  70. Cleanup ();
  71. throw new XmlException ("Error parsing stylesheet");
  72. }
  73. result = xsltParseStylesheetDoc (xmlDoc);
  74. Cleanup ();
  75. if (result == IntPtr.Zero)
  76. throw new XmlException ("Error creating stylesheet");
  77. return result;
  78. }
  79. // Loads the XSLT stylesheet contained in the XmlReader
  80. public void Load (XmlReader stylesheet)
  81. {
  82. FreeStylesheetIfNeeded ();
  83. // Create a document for the stylesheet
  84. XmlDocument doc = new XmlDocument ();
  85. doc.Load (stylesheet);
  86. // Store the XML in a StringBuilder
  87. StringWriter sr = new UTF8StringWriter ();
  88. XmlTextWriter writer = new XmlTextWriter (sr);
  89. doc.Save (writer);
  90. this.stylesheet = GetStylesheetFromString (sr.GetStringBuilder ().ToString ());
  91. Cleanup ();
  92. if (this.stylesheet == IntPtr.Zero)
  93. throw new XmlException ("Error creating stylesheet");
  94. }
  95. // Loads the XSLT stylesheet contained in the XPathNavigator
  96. public void Load (XPathNavigator stylesheet)
  97. {
  98. FreeStylesheetIfNeeded ();
  99. StringWriter sr = new UTF8StringWriter ();
  100. Save (stylesheet, sr);
  101. this.stylesheet = GetStylesheetFromString (sr.GetStringBuilder ().ToString ());
  102. Cleanup ();
  103. if (this.stylesheet == IntPtr.Zero)
  104. throw new XmlException ("Error creating stylesheet");
  105. }
  106. [MonoTODO("use the resolver")]
  107. // Loads the XSLT stylesheet contained in the IXPathNavigable.
  108. public void Load (IXPathNavigable stylesheet, XmlResolver resolver)
  109. {
  110. Load (stylesheet);
  111. }
  112. [MonoTODO("use the resolver")]
  113. // Loads the XSLT stylesheet specified by a URL.
  114. public void Load (string url, XmlResolver resolver)
  115. {
  116. Load (url);
  117. }
  118. [MonoTODO("use the resolver")]
  119. // Loads the XSLT stylesheet contained in the XmlReader
  120. public void Load (XmlReader stylesheet, XmlResolver resolver)
  121. {
  122. Load (stylesheet);
  123. }
  124. [MonoTODO("use the resolver")]
  125. // Loads the XSLT stylesheet contained in the XPathNavigator
  126. public void Load (XPathNavigator stylesheet, XmlResolver resolver)
  127. {
  128. Load (stylesheet);
  129. }
  130. // Transforms the XML data in the IXPathNavigable using
  131. // the specified args and outputs the result to an XmlReader.
  132. public XmlReader Transform (IXPathNavigable input, XsltArgumentList args)
  133. {
  134. if (input == null)
  135. throw new ArgumentNullException ("input");
  136. return Transform (input.CreateNavigator (), args);
  137. }
  138. // Transforms the XML data in the input file and outputs
  139. // the result to an output file.
  140. public void Transform (string inputfile, string outputfile)
  141. {
  142. IntPtr xmlDocument = IntPtr.Zero;
  143. IntPtr resultDocument = IntPtr.Zero;
  144. try {
  145. xmlDocument = xmlParseFile (inputfile);
  146. if (xmlDocument == IntPtr.Zero)
  147. throw new XmlException ("Error parsing input file");
  148. resultDocument = ApplyStylesheet (xmlDocument, null, null);
  149. if (-1 == xsltSaveResultToFilename (outputfile, resultDocument, stylesheet, 0))
  150. throw new XmlException ("Error in xsltSaveResultToFilename");
  151. } finally {
  152. if (xmlDocument != IntPtr.Zero)
  153. xmlFreeDoc (xmlDocument);
  154. if (resultDocument != IntPtr.Zero)
  155. xmlFreeDoc (resultDocument);
  156. Cleanup ();
  157. }
  158. }
  159. IntPtr ApplyStylesheet (IntPtr doc, string[] argArr, Hashtable extobjects)
  160. {
  161. if (stylesheet == IntPtr.Zero)
  162. throw new XmlException ("No style sheet!");
  163. IntPtr result;
  164. if (extobjects == null || extobjects.Count == 0) {
  165. // If there are no extension objects, use the simple (old) method.
  166. result = xsltApplyStylesheet (stylesheet, doc, argArr);
  167. } else {
  168. // If there are extension objects, create a context and register the functions.
  169. IntPtr context = xsltNewTransformContext(stylesheet, doc);
  170. if (context == IntPtr.Zero) throw new XmlException("Error creating transformation context.");
  171. try {
  172. foreach (string ns in extobjects.Keys) {
  173. object ext = extobjects[ns];
  174. if (extensionObjectCache.ContainsKey(ext)) {
  175. foreach (ExtensionFunctionHolder ef in (ArrayList)extensionObjectCache[ext]) {
  176. int ret = xsltRegisterExtFunction(context, ef.name, ef.ns, ef.func);
  177. if (ret != 0) throw new XmlException("Could not reregister extension function " + ef.name + " in " + ef.ns);
  178. }
  179. } else {
  180. object extsrc;
  181. System.Type type;
  182. System.Collections.IEnumerable methods;
  183. // As an added bonus, if the extension object is a UseStaticMethods object
  184. // (defined below), then add the static methods of the specified type.
  185. if (ext is UseStaticMethods) {
  186. type = ((UseStaticMethods)ext).Type;
  187. methods = type.GetMethods(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);
  188. extsrc = null;
  189. } else {
  190. extsrc = ext;
  191. type = ext.GetType();
  192. methods = type.GetMethods();
  193. }
  194. ArrayList functionstocache = new ArrayList();
  195. Hashtable alreadyadded = new Hashtable ();
  196. foreach (System.Reflection.MethodInfo mi in methods) {
  197. if (alreadyadded.ContainsKey(mi.Name)) continue; // don't add twice
  198. alreadyadded[mi.Name] = 1;
  199. // Simple extension function delegate
  200. ExtensionFunction func = new ExtensionFunction(new ReflectedExtensionFunction(type, extsrc, mi.Name).Function);
  201. // Delegate for libxslt library call
  202. libxsltXPathFunction libfunc = new libxsltXPathFunction(new ExtensionFunctionWrapper(func).Function);
  203. int ret = xsltRegisterExtFunction(context, mi.Name, ns, libfunc);
  204. if (ret != 0) throw new XmlException("Could not register extension function " + mi.DeclaringType.FullName + "." + mi.Name + " in " + ns);
  205. ExtensionFunctionHolder efh;
  206. efh.name = mi.Name;
  207. efh.ns = ns;
  208. efh.func = libfunc;
  209. functionstocache.Add(efh);
  210. }
  211. extensionObjectCache[ext] = functionstocache;
  212. }
  213. }
  214. result = xsltApplyStylesheetUser(stylesheet, doc, argArr, null, IntPtr.Zero, context);
  215. } finally {
  216. xsltFreeTransformContext(context);
  217. }
  218. }
  219. if (result == IntPtr.Zero)
  220. throw new XmlException ("Error applying style sheet");
  221. return result;
  222. }
  223. static void Cleanup ()
  224. {
  225. xsltCleanupGlobals ();
  226. xmlCleanupParser ();
  227. }
  228. static string GetStringFromDocument (IntPtr doc, IntPtr stylesheet)
  229. {
  230. IntPtr mem = IntPtr.Zero;
  231. int size = 0;
  232. int res = xsltSaveResultToString (ref mem, ref size, doc,
  233. stylesheet);
  234. if (res == -1)
  235. throw new XmlException ("xsltSaveResultToString () failed.");
  236. string docStr = Marshal.PtrToStringAnsi (mem, size);
  237. Marshal.FreeHGlobal (mem);
  238. return docStr;
  239. }
  240. string ApplyStylesheetAndGetString (IntPtr doc, string[] argArr, Hashtable extobjects)
  241. {
  242. IntPtr xmlOutput = ApplyStylesheet (doc, argArr, extobjects);
  243. string strOutput = GetStringFromDocument (xmlOutput, stylesheet);
  244. xmlFreeDoc (xmlOutput);
  245. return strOutput;
  246. }
  247. IntPtr GetDocumentFromNavigator (XPathNavigator nav)
  248. {
  249. StringWriter sr = new UTF8StringWriter ();
  250. Save (nav, sr);
  251. IntPtr xmlInput = xmlParseDoc (sr.GetStringBuilder ().ToString ());
  252. if (xmlInput == IntPtr.Zero)
  253. throw new XmlException ("Error getting XML from input");
  254. return xmlInput;
  255. }
  256. [MonoTODO("Node Set and Node Fragment Parameters and Extension Objects")]
  257. // Transforms the XML data in the XPathNavigator using
  258. // the specified args and outputs the result to an XmlReader.
  259. public XmlReader Transform (XPathNavigator input, XsltArgumentList args)
  260. {
  261. IntPtr xmlInput = GetDocumentFromNavigator (input);
  262. string[] argArr = null;
  263. Hashtable extensionObjects = null;
  264. if (args != null) {
  265. extensionObjects = args.extensionObjects;
  266. argArr = new string[args.parameters.Count * 2 + 1];
  267. int index = 0;
  268. foreach (object key in args.parameters.Keys) {
  269. argArr [index++] = key.ToString();
  270. object value = args.parameters [key];
  271. if (value is Boolean)
  272. argArr [index++] = XmlConvert.ToString((bool) value); // FIXME: How to encode it for libxslt?
  273. else if (value is Double)
  274. argArr [index++] = XmlConvert.ToString((double) value); // FIXME: How to encode infinity's and Nan?
  275. else
  276. argArr [index++] = "'" + value.ToString() + "'"; // FIXME: How to encode "'"?
  277. }
  278. argArr[index] = null;
  279. }
  280. string xslOutputString = ApplyStylesheetAndGetString (xmlInput, argArr, extensionObjects);
  281. xmlFreeDoc (xmlInput);
  282. Cleanup ();
  283. return new XmlTextReader (new StringReader (xslOutputString));
  284. }
  285. // Transforms the XML data in the IXPathNavigable using
  286. // the specified args and outputs the result to a Stream.
  287. public void Transform (IXPathNavigable input, XsltArgumentList args, Stream output)
  288. {
  289. if (input == null)
  290. throw new ArgumentNullException ("input");
  291. Transform (input.CreateNavigator (), args, new StreamWriter (output));
  292. }
  293. // Transforms the XML data in the IXPathNavigable using
  294. // the specified args and outputs the result to a TextWriter.
  295. public void Transform (IXPathNavigable input, XsltArgumentList args, TextWriter output)
  296. {
  297. if (input == null)
  298. throw new ArgumentNullException ("input");
  299. Transform (input.CreateNavigator (), args, output);
  300. }
  301. // Transforms the XML data in the IXPathNavigable using
  302. // the specified args and outputs the result to an XmlWriter.
  303. public void Transform (IXPathNavigable input, XsltArgumentList args, XmlWriter output)
  304. {
  305. if (input == null)
  306. throw new ArgumentNullException ("input");
  307. Transform (input.CreateNavigator (), args, output);
  308. }
  309. // Transforms the XML data in the XPathNavigator using
  310. // the specified args and outputs the result to a Stream.
  311. public void Transform (XPathNavigator input, XsltArgumentList args, Stream output)
  312. {
  313. Transform (input, args, new StreamWriter (output));
  314. }
  315. // Transforms the XML data in the XPathNavigator using
  316. // the specified args and outputs the result to a TextWriter.
  317. [MonoTODO("Node Set and Node Fragment Parameters and Extension Objects")]
  318. public void Transform (XPathNavigator input, XsltArgumentList args, TextWriter output)
  319. {
  320. if (input == null)
  321. throw new ArgumentNullException ("input");
  322. if (output == null)
  323. throw new ArgumentNullException ("output");
  324. IntPtr inputDoc = GetDocumentFromNavigator (input);
  325. string[] argArr = null;
  326. Hashtable extensionObjects = null;
  327. if (args != null) {
  328. extensionObjects = args.extensionObjects;
  329. argArr = new string[args.parameters.Count * 2 + 1];
  330. int index = 0;
  331. foreach (object key in args.parameters.Keys) {
  332. argArr [index++] = key.ToString();
  333. object value = args.parameters [key];
  334. if (value is Boolean)
  335. argArr [index++] = XmlConvert.ToString((bool) value); // FIXME: How to encode it for libxslt?
  336. else if (value is Double)
  337. argArr [index++] = XmlConvert.ToString((double) value); // FIXME: How to encode infinity's and Nan?
  338. else
  339. argArr [index++] = "'" + value.ToString() + "'"; // FIXME: How to encode "'"?
  340. }
  341. argArr[index] = null;
  342. }
  343. string transform = ApplyStylesheetAndGetString (inputDoc, argArr, extensionObjects);
  344. xmlFreeDoc (inputDoc);
  345. Cleanup ();
  346. output.Write (transform);
  347. output.Flush ();
  348. }
  349. // Transforms the XML data in the XPathNavigator using
  350. // the specified args and outputs the result to an XmlWriter.
  351. public void Transform (XPathNavigator input, XsltArgumentList args, XmlWriter output)
  352. {
  353. StringWriter writer = new UTF8StringWriter ();
  354. Transform (input, args, writer);
  355. output.WriteRaw (writer.GetStringBuilder ().ToString ());
  356. output.Flush ();
  357. }
  358. static void Save (XmlReader rdr, TextWriter baseWriter)
  359. {
  360. XmlTextWriter writer = new XmlTextWriter (baseWriter);
  361. while (rdr.Read ()) {
  362. switch (rdr.NodeType) {
  363. case XmlNodeType.CDATA:
  364. writer.WriteCData (rdr.Value);
  365. break;
  366. case XmlNodeType.Comment:
  367. writer.WriteComment (rdr.Value);
  368. break;
  369. case XmlNodeType.DocumentType:
  370. writer.WriteDocType (rdr.Value, null, null, null);
  371. break;
  372. case XmlNodeType.Element:
  373. writer.WriteStartElement (rdr.Name, rdr.Value);
  374. while (rdr.MoveToNextAttribute ())
  375. writer.WriteAttributes (rdr, true);
  376. break;
  377. case XmlNodeType.EndElement:
  378. writer.WriteEndElement ();
  379. break;
  380. case XmlNodeType.ProcessingInstruction:
  381. writer.WriteProcessingInstruction (rdr.Name, rdr.Value);
  382. break;
  383. case XmlNodeType.Text:
  384. writer.WriteString (rdr.Value);
  385. break;
  386. case XmlNodeType.Whitespace:
  387. writer.WriteWhitespace (rdr.Value);
  388. break;
  389. case XmlNodeType.XmlDeclaration:
  390. writer.WriteStartDocument ();
  391. break;
  392. }
  393. }
  394. writer.Close ();
  395. }
  396. static void Save (XPathNavigator navigator, TextWriter writer)
  397. {
  398. XmlTextWriter xmlWriter = new XmlTextWriter (writer);
  399. WriteTree (navigator, xmlWriter);
  400. xmlWriter.WriteEndDocument ();
  401. xmlWriter.Flush ();
  402. }
  403. // Walks the XPathNavigator tree recursively
  404. static void WriteTree (XPathNavigator navigator, XmlTextWriter writer)
  405. {
  406. WriteCurrentNode (navigator, writer);
  407. if (navigator.MoveToFirstAttribute ()) {
  408. do {
  409. WriteCurrentNode (navigator, writer);
  410. } while (navigator.MoveToNextAttribute ());
  411. navigator.MoveToParent ();
  412. }
  413. if (navigator.MoveToFirstChild ()) {
  414. do {
  415. WriteTree (navigator, writer);
  416. } while (navigator.MoveToNext ());
  417. navigator.MoveToParent ();
  418. if (navigator.NodeType != XPathNodeType.Root)
  419. writer.WriteEndElement ();
  420. } else if (navigator.NodeType == XPathNodeType.Element) {
  421. writer.WriteEndElement ();
  422. }
  423. }
  424. // Format the output
  425. static void WriteCurrentNode (XPathNavigator navigator, XmlTextWriter writer)
  426. {
  427. switch (navigator.NodeType) {
  428. case XPathNodeType.Root:
  429. writer.WriteStartDocument ();
  430. break;
  431. case XPathNodeType.Attribute:
  432. writer.WriteAttributeString (navigator.Name, navigator.Value);
  433. break;
  434. case XPathNodeType.Comment:
  435. writer.WriteComment (navigator.Value);
  436. break;
  437. case XPathNodeType.Element:
  438. writer.WriteStartElement (navigator.Name);
  439. break;
  440. case XPathNodeType.ProcessingInstruction:
  441. writer.WriteProcessingInstruction (navigator.Name, navigator.Value);
  442. break;
  443. case XPathNodeType.Text:
  444. writer.WriteString (navigator.Value);
  445. break;
  446. case XPathNodeType.SignificantWhitespace:
  447. case XPathNodeType.Whitespace:
  448. writer.WriteWhitespace (navigator.Value);
  449. break;
  450. }
  451. }
  452. // Extension Objects
  453. internal delegate object ExtensionFunction(object[] args);
  454. private struct ExtensionFunctionHolder {
  455. public libxsltXPathFunction func;
  456. public string ns, name;
  457. }
  458. // Wraps an ExtensionFunction into a function that is callable from the libxslt library.
  459. private unsafe class ExtensionFunctionWrapper {
  460. private readonly ExtensionFunction func;
  461. public ExtensionFunctionWrapper(ExtensionFunction func) {
  462. if ((object)func == null) throw new ArgumentNullException("func");
  463. this.func = func;
  464. }
  465. public unsafe void Function(IntPtr xpath_ctxt, int nargs) {
  466. // Convert XPath arguments into "managed" arguments
  467. System.Collections.ArrayList args = new System.Collections.ArrayList();
  468. for (int i = 0; i < nargs; i++) {
  469. xpathobject* aptr = valuePop(xpath_ctxt);
  470. if (aptr->type == 2) // Booleans
  471. args.Add( xmlXPathCastToBoolean(aptr) == 0 ? false : true );
  472. else if (aptr->type == 3) // Doubles
  473. args.Add( xmlXPathCastToNumber(aptr));
  474. else if (aptr->type == 4) // Strings
  475. args.Add( xmlXPathCastToString(aptr));
  476. else if (aptr->type == 1 && aptr->nodesetptr != null) { // Node Sets ==> ArrayList of strings
  477. System.Collections.ArrayList a = new System.Collections.ArrayList();
  478. for (int ni = 0; ni < aptr->nodesetptr->count; ni++) {
  479. xpathobject *n = xmlXPathNewNodeSet(aptr->nodesetptr->nodes[ni]);
  480. valuePush(xpath_ctxt, n);
  481. xmlXPathStringFunction(xpath_ctxt, 1);
  482. a.Add(xmlXPathCastToString(valuePop(xpath_ctxt)));
  483. xmlXPathFreeObject(n);
  484. }
  485. args.Add(a);
  486. } else { // Anything else => string
  487. valuePush(xpath_ctxt, aptr);
  488. xmlXPathStringFunction(xpath_ctxt, 1);
  489. args.Add(xmlXPathCastToString(valuePop(xpath_ctxt)));
  490. }
  491. xmlXPathFreeObject(aptr);
  492. }
  493. args.Reverse();
  494. object ret = func(args.ToArray());
  495. // Convert the result back to an XPath object
  496. if (ret == null) // null => ""
  497. valuePush(xpath_ctxt, xmlXPathNewCString(""));
  498. else if (ret is bool) // Booleans
  499. valuePush(xpath_ctxt, xmlXPathNewBoolean((bool)ret ? 1 : 0));
  500. else if (ret is int || ret is long || ret is double || ret is float || ret is decimal)
  501. // Numbers
  502. valuePush(xpath_ctxt, xmlXPathNewFloat((double)ret));
  503. else // Everything else => String
  504. valuePush(xpath_ctxt, xmlXPathNewCString(ret.ToString()));
  505. }
  506. }
  507. // Provides a delegate for calling a late-bound method of a type with a given name.
  508. // Determines method based on types of arguments.
  509. private class ReflectedExtensionFunction {
  510. System.Type type;
  511. object src;
  512. string methodname;
  513. public ReflectedExtensionFunction(System.Type type, object src, string methodname) { this.type = type; this.src = src; this.methodname = methodname; }
  514. public object Function(object[] args) {
  515. // Construct arg type array, and a stringified version in case of problem
  516. System.Type[] argtypes = new System.Type[args.Length];
  517. string argtypelist = null;
  518. for (int i = 0; i < args.Length; i++) {
  519. argtypes[i] = (args[i] == null ? typeof(object) : args[i].GetType() );
  520. if (argtypelist != null) argtypelist += ", ";
  521. argtypelist += argtypes[i].FullName;
  522. }
  523. if (argtypelist == null) argtypelist = "";
  524. // Find the method
  525. System.Reflection.MethodInfo mi = type.GetMethod(methodname, (src == null ? BF.Static : BF.Instance | BF.Static) | BF.Public, null, argtypes, null);
  526. // No method?
  527. if (mi == null) throw new XmlException("No applicable function for " + methodname + " takes (" + argtypelist + ")");
  528. if (!mi.IsStatic && src == null) throw new XmlException("Attempt to call static method without instantiated extension object.");
  529. // Invoke
  530. return mi.Invoke(src, args);
  531. }
  532. }
  533. // Special Mono-specific class that allows static methods of a type to
  534. // be bound without needing an instance of that type. Useful for
  535. // registering System.Math functions, for example.
  536. // Usage: args.AddExtensionObject( new XslTransform.UseStaticMethods(typeof(thetype)) );
  537. public sealed class UseStaticMethods {
  538. public readonly System.Type Type;
  539. public UseStaticMethods(System.Type Type) { this.Type = Type; }
  540. }
  541. #endregion
  542. #region Calls to external libraries
  543. // libxslt
  544. [DllImport ("xslt")]
  545. static extern IntPtr xsltParseStylesheetFile (string filename);
  546. [DllImport ("xslt")]
  547. static extern IntPtr xsltParseStylesheetDoc (IntPtr docPtr);
  548. [DllImport ("xslt")]
  549. static extern IntPtr xsltApplyStylesheet (IntPtr stylePtr, IntPtr DocPtr, string[] argPtr);
  550. [DllImport ("xslt")]
  551. static extern int xsltSaveResultToString (ref IntPtr stringPtr, ref int stringLen,
  552. IntPtr docPtr, IntPtr stylePtr);
  553. [DllImport ("xslt")]
  554. static extern int xsltSaveResultToFilename (string URI, IntPtr doc, IntPtr styleSheet, int compression);
  555. [DllImport ("xslt")]
  556. static extern void xsltCleanupGlobals ();
  557. [DllImport ("xslt")]
  558. static extern void xsltFreeStylesheet (IntPtr cur);
  559. // libxml2
  560. [DllImport ("xml2")]
  561. static extern IntPtr xmlNewDoc (string version);
  562. [DllImport ("xml2")]
  563. static extern int xmlSaveFile (string filename, IntPtr cur);
  564. [DllImport ("xml2")]
  565. static extern IntPtr xmlParseFile (string filename);
  566. [DllImport ("xml2")]
  567. static extern IntPtr xmlParseDoc (string document);
  568. [DllImport ("xml2")]
  569. static extern void xmlFreeDoc (IntPtr doc);
  570. [DllImport ("xml2")]
  571. static extern void xmlCleanupParser ();
  572. [DllImport ("xml2")]
  573. static extern void xmlDocDumpMemory (IntPtr doc, ref IntPtr mem, ref int size);
  574. [DllImport ("xml2")]
  575. static extern void xmlFree (IntPtr data);
  576. // Functions and structures for extension objects
  577. [DllImport ("xslt")]
  578. static extern IntPtr xsltNewTransformContext (IntPtr style, IntPtr doc);
  579. [DllImport ("xslt")]
  580. static extern void xsltFreeTransformContext (IntPtr context);
  581. [DllImport ("xslt")]
  582. static extern IntPtr xsltApplyStylesheetUser (IntPtr stylePtr, IntPtr DocPtr, string[] argPtr, string output, IntPtr profile, IntPtr context);
  583. [DllImport ("xslt")]
  584. static extern int xsltRegisterExtFunction (IntPtr context, string name, string uri, libxsltXPathFunction function);
  585. [DllImport ("xml2")]
  586. unsafe static extern xpathobject* valuePop (IntPtr context);
  587. [DllImport ("xml2")]
  588. unsafe static extern void valuePush (IntPtr context, xpathobject* data);
  589. [DllImport("xml2")]
  590. unsafe static extern void xmlXPathFreeObject(xpathobject* obj);
  591. [DllImport("xml2")]
  592. unsafe static extern xpathobject* xmlXPathNewCString(string str);
  593. [DllImport("xml2")]
  594. unsafe static extern xpathobject* xmlXPathNewFloat(double val);
  595. [DllImport("xml2")]
  596. unsafe static extern xpathobject* xmlXPathNewBoolean(int val);
  597. [DllImport("xml2")]
  598. unsafe static extern xpathobject* xmlXPathNewNodeSet(IntPtr nodeptr);
  599. [DllImport("xml2")]
  600. unsafe static extern int xmlXPathCastToBoolean(xpathobject* val);
  601. [DllImport("xml2")]
  602. unsafe static extern double xmlXPathCastToNumber(xpathobject* val);
  603. [DllImport("xml2")]
  604. unsafe static extern string xmlXPathCastToString(xpathobject* val);
  605. [DllImport("xml2")]
  606. static extern void xmlXPathStringFunction(IntPtr context, int nargs);
  607. private delegate void libxsltXPathFunction(IntPtr xpath_ctxt, int nargs);
  608. private struct xpathobject {
  609. public int type;
  610. public xmlnodelist* nodesetptr;
  611. }
  612. private struct xmlnodelist {
  613. public int count;
  614. public int allocated;
  615. public IntPtr* nodes;
  616. }
  617. #endregion
  618. // This classes just makes the base class use 'encoding="utf-8"'
  619. class UTF8StringWriter : StringWriter
  620. {
  621. static Encoding encoding = new UTF8Encoding (false);
  622. public override Encoding Encoding {
  623. get {
  624. return encoding;
  625. }
  626. }
  627. }
  628. }
  629. }