Creating a Reusable XSLT Class
By now you should feel comfortable working with the different classes within the System.Xml assembly that can be used to perform XSL transformations. However, wouldn't it be nice if you could write a generic class that doesn't require any knowledge of the XPathDocument or XslTransform classes (and their supporting classes) to be used? Not only would such a class provide more productive programming, but it would also allow your ASP.NET applications to leverage all the benefits offered by following object-oriented programming techniques.
The code in Listing 7.15 shows a generic class that allows an ASP.NET programmer to transform an XML document using XSLT without any knowledge of XSLT-specific classes. This code leverages well-known classes such as HashTable to accomplish the transformation.
Listing 7.15 A Reusable XSLT Transformation Class (xsltTransform.cs)
1: namespace XsltTransformation { 2: 3: using System; 4: using System.Xml; 5: using System.Xml.XPath; 6: using System.Xml.Xsl; 7: using System.Collections; 8: using System.IO; 9: using System.Text; 10: 11: /// <summary> 12: /// A generic XSL Transformation Class for use in ASP.NET pages 13: /// </summary> 14: public class XsltTransform { 15: 16: public static string TransformXml(string xmlPath,string xsltPath, 17: Hashtable xsltParams,Hashtable xsltObjects) { 18: 19: StringBuilder sb = new StringBuilder(); 20: StringWriter sw = new StringWriter(sb); 21: try { 22: XPathDocument doc = new XPathDocument(xmlPath); 23: XsltArgumentList args = new XsltArgumentList(); 24: XslTransform xslDoc = new XslTransform(); 25: xslDoc.Load(xsltPath); 26: 27: //Fill XsltArgumentList if necessary 28: if (xsltParams != null) { 29: IDictionaryEnumerator pEnumerator = 30: xsltParams.GetEnumerator(); 31: while (pEnumerator.MoveNext()) { 32: args.AddParam(pEnumerator.Key.ToString(),"", 33: pEnumerator.Value); 34: } 35: } 36: if (xsltObjects != null) { 37: IDictionaryEnumerator pEnumerator = 38: xsltObjects.GetEnumerator(); 39: while (pEnumerator.MoveNext()) { 40: args.AddExtensionObject(pEnumerator.Key.ToString(), 41: pEnumerator.Value); 42: } 43: } 44: xslDoc.Transform(doc,args,sw); 45: return sb.ToString(); 46: } 47: catch (Exception exp) { 48: return exp.ToString(); 49: } 50: finally { 51: sw.Close(); 52: } 53: } 54: } //XsltTransform 55: } // XsltTransformation namespace
Having a reusable class for XSL transformations results in much cleaner ASP.NET code, as Listing 7.16 shows.
Listing 7.16 Using the XsltTransform Class in ASP.NET (xsltTransform.aspx)
public void Page_Load(object sender, System.EventArgs e) { string xmlPath = Server.MapPath("Listing7.1.xml"); string xslPath = Server.MapPath("xsltExtension.xsl"); //Create the External Object XsltDateTime xsltExtObj = new XsltDateTime(); //Create Hashtables to hold params and external objects //If none are needed, pass null into the TransformXml() method instead Hashtable xsltParams = new Hashtable(); Hashtable xsltObjects = new Hashtable(); //Fill the Hashtables with the params and external objects xsltParams.Add("golferName","Heedy"); xsltObjects.Add("urn:xsltExtension-DateTime",xsltExtObj); //Call the custom XsltTransform class's TransformXml method string xsl = XsltTransform.TransformXml(xmlPath,xslPath, xsltParams,xsltObjects); Response.Write(xsl); }
As this book was going to press, I wrote a new article demonstrating how the techniques shown in Listing 7.15 can be used to create an ASP.NET server control geared at targeting multiple devices using XML and XSLT. This article will appear in the premier issue (September 2001) of Visual Studio Magazine (http://www.devx.com), and the code can be downloaded from the DevX site or from the CodeBank section of http://www.TomorrowsLearning.com.
The Asp:Xml Web Control
The .NET framework also comes with a prebuilt Web control that can be used for doing simple XSL transformations in ASP.NET pages. This control allows the XML document source and XSLT style sheet source to be set using attributes. Listing 7.17 shows how the control is used.
Listing 7.17 Using the asp:Xml Web Control
1: <html> 2: <body> 3: <asp:Xml ID="xslTransform" Runat="server" 4: DocumentSource="Listing7.1.xml" 5: TransformSource="Listing7.2.xsl"> 6: </asp:Xml> 7: </body> 8: </html>
In situations where the values of the DocumentSource and/or TransformSource attributes are not known until runtime, they can be assigned dynamically, as Listing 7.18 shows.
Listing 7.18 Dynamically Assigning Source Documents to the asp:Xml Web Control
1: <script language="C#" runat="server"> 2: void Page_Load(object sender, System.EventArgs e) { 3: xslTransform.DocumentSource = "Listing7.1.xml"; 4: xslTransform.TransformSource = "Listing7.2.xsl"; 5: } 6: </script> 7: <html> 8: <body> 9: <asp:Xml ID="xslTransform" Runat="server"></asp:Xml> 10: </body> 11: </html>
The asp:Xml server control also allows DOM structures to be passed into it programmatically using the Document and Transform properties:
1: <%@Import Namespace="System.Xml"%> 2: <%@Import Namespace="System.Xml.Xsl"%> 3: <script language="C#" runat="server"> 4: void Page_Load(object sender, System.EventArgs e) { 5: XmlDocument doc = new XmlDocument(); 6: doc.Load(Server.MapPath("Listing7.1.xml")); 7: XslTransform trans = new XslTransform(); 8: trans.Load(Server.MapPath("Listing7.2.xsl")); 9: xslTransform.Document = doc; 10: xslTransform.Transform = trans; 11: } 12: </script> 13: <html> 14: <body> 15: <asp:Xml ID="xslTransform" Runat="server"> 16: </asp:Xml> 17: </body>18: </html>