XslTransform.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811
  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.MoveToFirstNamespace (XPathNamespaceScope.Local)) {
  408. do {
  409. WriteCurrentNode (navigator, writer);
  410. } while (navigator.MoveToNextNamespace (XPathNamespaceScope.Local));
  411. navigator.MoveToParent ();
  412. }
  413. if (navigator.MoveToFirstAttribute ()) {
  414. do {
  415. WriteCurrentNode (navigator, writer);
  416. } while (navigator.MoveToNextAttribute ());
  417. navigator.MoveToParent ();
  418. }
  419. if (navigator.MoveToFirstChild ()) {
  420. do {
  421. WriteTree (navigator, writer);
  422. } while (navigator.MoveToNext ());
  423. navigator.MoveToParent ();
  424. if (navigator.NodeType != XPathNodeType.Root)
  425. writer.WriteEndElement ();
  426. } else if (navigator.NodeType == XPathNodeType.Element) {
  427. writer.WriteEndElement ();
  428. }
  429. }
  430. // Format the output
  431. static void WriteCurrentNode (XPathNavigator navigator, XmlTextWriter writer)
  432. {
  433. switch (navigator.NodeType) {
  434. case XPathNodeType.Root:
  435. writer.WriteStartDocument ();
  436. break;
  437. case XPathNodeType.Namespace:
  438. if (navigator.Name == String.Empty)
  439. writer.WriteAttributeString ("xmlns", navigator.Value);
  440. else
  441. writer.WriteAttributeString ("xmlns",
  442. navigator.Name,
  443. "http://www.w3.org/2000/xmlns/",
  444. navigator.Value);
  445. break;
  446. case XPathNodeType.Attribute:
  447. writer.WriteAttributeString (navigator.Name, navigator.Value);
  448. break;
  449. case XPathNodeType.Comment:
  450. writer.WriteComment (navigator.Value);
  451. break;
  452. case XPathNodeType.Element:
  453. writer.WriteStartElement (navigator.Name);
  454. break;
  455. case XPathNodeType.ProcessingInstruction:
  456. writer.WriteProcessingInstruction (navigator.Name, navigator.Value);
  457. break;
  458. case XPathNodeType.Text:
  459. writer.WriteString (navigator.Value);
  460. break;
  461. case XPathNodeType.SignificantWhitespace:
  462. case XPathNodeType.Whitespace:
  463. writer.WriteWhitespace (navigator.Value);
  464. break;
  465. }
  466. }
  467. // Extension Objects
  468. internal delegate object ExtensionFunction(object[] args);
  469. private struct ExtensionFunctionHolder {
  470. public libxsltXPathFunction func;
  471. public string ns, name;
  472. }
  473. // Wraps an ExtensionFunction into a function that is callable from the libxslt library.
  474. private unsafe class ExtensionFunctionWrapper {
  475. private readonly ExtensionFunction func;
  476. public ExtensionFunctionWrapper(ExtensionFunction func) {
  477. if ((object)func == null) throw new ArgumentNullException("func");
  478. this.func = func;
  479. }
  480. public unsafe void Function(IntPtr xpath_ctxt, int nargs) {
  481. // Convert XPath arguments into "managed" arguments
  482. System.Collections.ArrayList args = new System.Collections.ArrayList();
  483. for (int i = 0; i < nargs; i++) {
  484. xpathobject* aptr = valuePop(xpath_ctxt);
  485. if (aptr->type == 2) // Booleans
  486. args.Add( xmlXPathCastToBoolean(aptr) == 0 ? false : true );
  487. else if (aptr->type == 3) // Doubles
  488. args.Add( xmlXPathCastToNumber(aptr));
  489. else if (aptr->type == 4) // Strings
  490. args.Add( xmlXPathCastToString(aptr));
  491. else if (aptr->type == 1 && aptr->nodesetptr != null) { // Node Sets ==> ArrayList of strings
  492. System.Collections.ArrayList a = new System.Collections.ArrayList();
  493. for (int ni = 0; ni < aptr->nodesetptr->count; ni++) {
  494. xpathobject *n = xmlXPathNewNodeSet(aptr->nodesetptr->nodes[ni]);
  495. valuePush(xpath_ctxt, n);
  496. xmlXPathStringFunction(xpath_ctxt, 1);
  497. a.Add(xmlXPathCastToString(valuePop(xpath_ctxt)));
  498. xmlXPathFreeObject(n);
  499. }
  500. args.Add(a);
  501. } else { // Anything else => string
  502. valuePush(xpath_ctxt, aptr);
  503. xmlXPathStringFunction(xpath_ctxt, 1);
  504. args.Add(xmlXPathCastToString(valuePop(xpath_ctxt)));
  505. }
  506. xmlXPathFreeObject(aptr);
  507. }
  508. args.Reverse();
  509. object ret = func(args.ToArray());
  510. // Convert the result back to an XPath object
  511. if (ret == null) // null => ""
  512. valuePush(xpath_ctxt, xmlXPathNewCString(""));
  513. else if (ret is bool) // Booleans
  514. valuePush(xpath_ctxt, xmlXPathNewBoolean((bool)ret ? 1 : 0));
  515. else if (ret is int || ret is long || ret is double || ret is float || ret is decimal)
  516. // Numbers
  517. valuePush(xpath_ctxt, xmlXPathNewFloat((double)ret));
  518. else // Everything else => String
  519. valuePush(xpath_ctxt, xmlXPathNewCString(ret.ToString()));
  520. }
  521. }
  522. // Provides a delegate for calling a late-bound method of a type with a given name.
  523. // Determines method based on types of arguments.
  524. private class ReflectedExtensionFunction {
  525. System.Type type;
  526. object src;
  527. string methodname;
  528. public ReflectedExtensionFunction(System.Type type, object src, string methodname) { this.type = type; this.src = src; this.methodname = methodname; }
  529. public object Function(object[] args) {
  530. // Construct arg type array, and a stringified version in case of problem
  531. System.Type[] argtypes = new System.Type[args.Length];
  532. string argtypelist = null;
  533. for (int i = 0; i < args.Length; i++) {
  534. argtypes[i] = (args[i] == null ? typeof(object) : args[i].GetType() );
  535. if (argtypelist != null) argtypelist += ", ";
  536. argtypelist += argtypes[i].FullName;
  537. }
  538. if (argtypelist == null) argtypelist = "";
  539. // Find the method
  540. System.Reflection.MethodInfo mi = type.GetMethod(methodname, (src == null ? BF.Static : BF.Instance | BF.Static) | BF.Public, null, argtypes, null);
  541. // No method?
  542. if (mi == null) throw new XmlException("No applicable function for " + methodname + " takes (" + argtypelist + ")");
  543. if (!mi.IsStatic && src == null) throw new XmlException("Attempt to call static method without instantiated extension object.");
  544. // Invoke
  545. return mi.Invoke(src, args);
  546. }
  547. }
  548. // Special Mono-specific class that allows static methods of a type to
  549. // be bound without needing an instance of that type. Useful for
  550. // registering System.Math functions, for example.
  551. // Usage: args.AddExtensionObject( new XslTransform.UseStaticMethods(typeof(thetype)) );
  552. public sealed class UseStaticMethods {
  553. public readonly System.Type Type;
  554. public UseStaticMethods(System.Type Type) { this.Type = Type; }
  555. }
  556. #endregion
  557. #region Calls to external libraries
  558. // libxslt
  559. [DllImport ("xslt")]
  560. static extern IntPtr xsltParseStylesheetFile (string filename);
  561. [DllImport ("xslt")]
  562. static extern IntPtr xsltParseStylesheetDoc (IntPtr docPtr);
  563. [DllImport ("xslt")]
  564. static extern IntPtr xsltApplyStylesheet (IntPtr stylePtr, IntPtr DocPtr, string[] argPtr);
  565. [DllImport ("xslt")]
  566. static extern int xsltSaveResultToString (ref IntPtr stringPtr, ref int stringLen,
  567. IntPtr docPtr, IntPtr stylePtr);
  568. [DllImport ("xslt")]
  569. static extern int xsltSaveResultToFilename (string URI, IntPtr doc, IntPtr styleSheet, int compression);
  570. [DllImport ("xslt")]
  571. static extern void xsltCleanupGlobals ();
  572. [DllImport ("xslt")]
  573. static extern void xsltFreeStylesheet (IntPtr cur);
  574. // libxml2
  575. [DllImport ("xml2")]
  576. static extern IntPtr xmlNewDoc (string version);
  577. [DllImport ("xml2")]
  578. static extern int xmlSaveFile (string filename, IntPtr cur);
  579. [DllImport ("xml2")]
  580. static extern IntPtr xmlParseFile (string filename);
  581. [DllImport ("xml2")]
  582. static extern IntPtr xmlParseDoc (string document);
  583. [DllImport ("xml2")]
  584. static extern void xmlFreeDoc (IntPtr doc);
  585. [DllImport ("xml2")]
  586. static extern void xmlCleanupParser ();
  587. [DllImport ("xml2")]
  588. static extern void xmlDocDumpMemory (IntPtr doc, ref IntPtr mem, ref int size);
  589. [DllImport ("xml2")]
  590. static extern void xmlFree (IntPtr data);
  591. // Functions and structures for extension objects
  592. [DllImport ("xslt")]
  593. static extern IntPtr xsltNewTransformContext (IntPtr style, IntPtr doc);
  594. [DllImport ("xslt")]
  595. static extern void xsltFreeTransformContext (IntPtr context);
  596. [DllImport ("xslt")]
  597. static extern IntPtr xsltApplyStylesheetUser (IntPtr stylePtr, IntPtr DocPtr, string[] argPtr, string output, IntPtr profile, IntPtr context);
  598. [DllImport ("xslt")]
  599. static extern int xsltRegisterExtFunction (IntPtr context, string name, string uri, libxsltXPathFunction function);
  600. [DllImport ("xml2")]
  601. unsafe static extern xpathobject* valuePop (IntPtr context);
  602. [DllImport ("xml2")]
  603. unsafe static extern void valuePush (IntPtr context, xpathobject* data);
  604. [DllImport("xml2")]
  605. unsafe static extern void xmlXPathFreeObject(xpathobject* obj);
  606. [DllImport("xml2")]
  607. unsafe static extern xpathobject* xmlXPathNewCString(string str);
  608. [DllImport("xml2")]
  609. unsafe static extern xpathobject* xmlXPathNewFloat(double val);
  610. [DllImport("xml2")]
  611. unsafe static extern xpathobject* xmlXPathNewBoolean(int val);
  612. [DllImport("xml2")]
  613. unsafe static extern xpathobject* xmlXPathNewNodeSet(IntPtr nodeptr);
  614. [DllImport("xml2")]
  615. unsafe static extern int xmlXPathCastToBoolean(xpathobject* val);
  616. [DllImport("xml2")]
  617. unsafe static extern double xmlXPathCastToNumber(xpathobject* val);
  618. [DllImport("xml2")]
  619. unsafe static extern string xmlXPathCastToString(xpathobject* val);
  620. [DllImport("xml2")]
  621. static extern void xmlXPathStringFunction(IntPtr context, int nargs);
  622. private delegate void libxsltXPathFunction(IntPtr xpath_ctxt, int nargs);
  623. private struct xpathobject {
  624. public int type;
  625. public xmlnodelist* nodesetptr;
  626. }
  627. private struct xmlnodelist {
  628. public int count;
  629. public int allocated;
  630. public IntPtr* nodes;
  631. }
  632. #endregion
  633. // This classes just makes the base class use 'encoding="utf-8"'
  634. class UTF8StringWriter : StringWriter
  635. {
  636. static Encoding encoding = new UTF8Encoding (false);
  637. public override Encoding Encoding {
  638. get {
  639. return encoding;
  640. }
  641. }
  642. }
  643. }
  644. }