Today I was looking for a simple way to apply an XSL stylesheet to an XML document. I didn’t want resolvers, files, or anything like that. I wanted to take an XSL string and an XML string, and apply it to get the output.
I started to play around with the System.Xml stuff, and then remembered that one of the tools I use pretty much every day is a frickin XSL Transformer I wrote! What better place to look then somewhere I had already solved it.
The core of the code is around a Transformer class that can take in either two XmlDocuments or two strings and applies the Xsl to the Xml, returning both the XmlDocument and the Xml string:
1 using System;
2 using System.IO;
3 using System.Xml;
4 using System.Xml.Xsl;
5
6 namespace MobileHWY.DAL.MSSQLCommandMapper
7 {
8 ///
9 /// Helper class to wrap XSL transformations and provide
10 /// utilities for preparing documents
11 ///
12 public class Transformer
13 {
14
15 #region Declarations
16 private XmlDocument xmlDoc;
17 private XmlDocument xslDoc;
18 private XmlDocument transformedDoc;
19 private String transformedString;
20 #endregion
21
22 #region Constructors
23
24 public Transformer()
25 {
26
27 }
28
29 public Transformer(XmlDocument xmlDoc, XmlDocument xslDoc)
30 {
31 this.xmlDoc = xmlDoc;
32 this.xslDoc = xslDoc;
33 }
34
35 public Transformer(String xmlDoc, String xslDoc)
36 {
37 try
38 {
39 this.xmlDoc = ConvertStringToDocument(xmlDoc);
40 }
41 catch(Exception ex)
42 {
43 throw new Applic
ationException("An error occurred transforming the XML Document", ex);
44 }
45
46 try
47 {
48 this.xslDoc = ConvertStringToDocument(xslDoc);
49 }
50 catch(Exception ex)
51 {
52 throw new ApplicationException("An error occurred transforming the XSL Document", ex);
53 }
54 }
55
56 #endregion
57
58 #region Properties
59 public XmlDocument XmlDocument
60 {
61 get
62 {
63 return xmlDoc;
64 }
65
66 set
67 {
68 xmlDoc = value;
69 }
70 }
71
72 public XmlDocument XslDocument
73 {
74
75 get
76 {
77 return xslDoc;
78 }
79 set
80 {
81 xslDoc = value;
82 }
83 }
84
85 public XmlDocument TransformedDocument
86 {
87 get
88 {
89 return transformedDoc;
90 }
91 }
92
93 public String TransformedStrin
g
94 {
95
96 get
97 {
98 return transformedString;
99 }
100 }
101 #endregion
102
103 #region Methods
104 public void Transform()
105 {
106 if(!ValidateInput())
107 {
108 return;
109 }
110
111 //Set up the XSL transformer
112 XslTransform transformer = new XslTransform();
113
114 //Create a memory stream so we can transform the document into memory
115 //instead of to a file and wrap it with an XmlTextWriter.
116 MemoryStream memStream = new MemoryStream();
117 XmlTextWriter memWriter = new XmlTextWriter(memStream, null);
118
119 //Load the XSL Document into the transformer
120 transformer.Load(xslDoc, null, null);
121
122 //Transform the XML document using the loaded XSL and place the
123 //output in the memory stream
124 transformer.Transform(xmlDoc, null, memWriter, null);
125
126 //reset the byte position in the memory stream so we can read
127 //from the beginning
128 memStream.Position = 0;
129
130 //Create a reader to get the document back out of the memory stream
131 XmlTextReader outReader = new XmlTextReader(memStream);
132
133 //Create a writer to place it in. We will also be creating a seperate
134 //XmlTextWriter so we can control the formatting of the output.
135 StringWriter sw = new StringWriter();
136 XmlTextWriter outWriter = new XmlTextWriter(sw);
137
138 //Set up the output formatting instructions
139 outWriter.Formatting = Formatting.Indented;
140 outWriter.Indentation = 4;
141
142 //actually write our the document
143 outWriter.WriteNode(outReader, true);
144
145 //clean up after ourselves
146 outReader.Close();
147 outWriter.Close();
148
149 //place the results in the appropriate variables
150 transformedString = sw.ToString();
151 transformedDoc = ConvertStringToDocument(transformedString);
152
153 }
154
155 private XmlDocument ConvertStringToDocument(String doc)
156 {
157 XmlDocument mpDoc = new XmlDocument();
158 mpDoc.LoadXml(doc);
159 return mpDoc;
160 }
161
162 private Boolean ValidateInput()
163 {
164 if(xmlDoc == null)
165 {
166 throw new Exception("The XML Document must be loaded before calling Transform");
167 }
168 if(xslDoc == null)
169 {
170 throw new Exception("The XSL Document must be loaded before calling Transform");
171 }
172 return true;
173 }
174 #endregion
175
176 }
177 }
Here’s an example NUnit test showing how to use it:
public void TestTransformXmlDocument()
{
string xsl = ““
+ “
+ ” xmlns:xsl=\”http://www.w3.org/1999/XSL/Transform\”>”
+ ”
+ ” “
+ ” “
+ “”;
string xml = “
string expectedOutXml = ““;
XmlDocument xmlDoc = new Xm
lDocument();
xmlDoc.LoadXml(xml);
XmlDocument xslDoc = new XmlDocument();
xslDoc.LoadXml(xsl);
Transformer transformer = new Transformer(xmlDoc, xslDoc);
transformer.Transform();
Assert.AreEqual(expectedOutXml, transformer.TransformedString);
}
“Here’s an example NUnit test showing how to use it:”
As someone just getting test infected, I find that statement, even completely out of context, quite profound.