I wrote xslt script in the past to manipulate xml data and very often hitting brick wall because of its API limitation. With .NET and the rich and powerful xml library, the brick wall is brought down at least for this case. With all that said, I would like to share my code with this user group and hope that it might be beneficial to someone.
Please see source code and brief explanation included to see how it works.
Books.xml
<?xml version="1.0" encoding="UTF-8" ?> <books> <item> <name>'Mystery of the dark mind'</name> <paperback>yes</paperback> <price>10.00</price> </item> <item> <name>'History of the underworld'</name> <paperback>no</paperback> <price>5.00</price> </item></books>
/* CSharpObject="xxx:test is now a reference to the GetPrice object. CSharpObject:Discount(price) calls the Discount(double price) of the GetPrice object */ Books.xsl
<?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:CSharpObject="xxx:test"> <xsl:template match="/"> <html> <head> <title>Good books to read</title> </head> <body> <h3>Books that will clear your mind</h3> <xsl:for-each select="books/item"> <xsl:value-of select="name" /> <span style="padding-left:20px"> <xsl:value-of select="price" /> </span> <br /> Paperback: <xsl:value-of select="paperback" /> <div style="padding-left:20px"> Discount price is: <xsl:value-of select="CSharpObject:Discount(price)" /> </div> <br /> </xsl:for-each> </body> </html> </xsl:template></xsl:stylesheet>
XsltArgument.cs or whatever name you wish
using System;using System.IO;using System.Xml;using System.Xml.Xsl;using System.Xml.XPath;
namespace Test{ public class GetPrice { public GetPrice() {} // The Discount method is invoked from xslt script, not in C# code public double Discount(double Price) { return Price - 1.5; } public void TransformBooks() { try { // Create the XsltArgumentList to hold C# object XsltArgumentList XsltArg = new XsltArgumentList(); // Create C# object GetPrice gp = new GetPrice(); /* Add C# object gp to the list and associate it with a unique name "xxx:test". I set this namespace to bold so that you can easily see its relationship with the Books.xsl file */ XsltArg.AddExtensionObject("xxx:test", gp); XslTransform Xslt = new XslTransform(); Xslt.Load("Books.xsl"); XPathDocument Doc = new XPathDocument("Books.xml"); XPathNavigator Nav = Doc.CreateNavigator(); // books.htm will be created if it doesn't exist XmlTextWriter Writer = new XmlTextWriter("books.htm", null); try { /* Transform XML data using an XSLT stylesheet passing in the gp object which contains the Discount() method to be called by Books.xsl */ Xslt.Transform(Nav, XsltArg, Writer, null); Console.WriteLine("The transformation is done. " + "You can now open and view the books.htm in a browser."); } finally { Writer.Close(); } } catch(Exception ex) { Console.WriteLine(ex.Message); } } } public class Test { public static void Main(string[] args) { GetPrice gp = new GetPrice(); gp.TransformBooks(); } }}
Hope it helps
Great post and really helpful, i truly get a lot of plus in my bag, thnx.
but there's something i would like to ask, is about how to implement the namespace?
when you write : xmlns:CSharpObject="xxx:test"
whats the meaning of xxx and test in the context ?whats the role of the class implemented above ?and if it possible could you implement an example that show exactly what must we do to get the whole start (where would we put the class or the dll, how to refer to it, etc ...)
thnx advance.