A common requirement for many administrative Windows applications is the ability to create reports of various data. For smaller projects, a full reporting tool like Crystal Reports may be overkill, so we need to find a more economical solution. Much of the data used in a modern Windows application is directly available in the form of XML or can easily be converted into XML. Unfortunately, raw XML does not make for easy reading; however HTML viewed in a web browser does, so we need to get hold on some HTML instead of XML. XSL style sheets is the preferred way to convert XML to HTML.
Luckily for us, .NET supports all three formats very well and so we can just pick from its available classes. This fact makes this project a cheap and easy solution, just what we are looking for our small Windows application.
Usually when working with XML, XSL or HTML, we work with files. This may not be necessary, especially if your XML data is generated by your application. Same goes for HTML code, it does not have to be saved to file to be viewed in a web browser. So saving our data to file is a redundant step with no benefits. Instead, we will do all this in memory without going to the disk. A really flexible solution will also generate the XSL code, giving the user a possibility to adjust the format of a report. If the XSL is stored in a central place, like a database, style sheets can be added or altered whenever needed and directly available for all users. So working directly with XSL, XML and HTML have great advantages. However, I must admit that most of the .NET classes are geared to handle files and so the code gets lengthy since we need to create lots of temporary objects to achieve our goal, you will see for yourself in the next chapter.
In this demo, we will use a
Listview control holding some data and use that data to produce some striking reports. The user, through the Format dialog, will be able to change a wide range of parameters (well, four to be honest) to customize the look and feel of the reports. A real application could also allow the user to decide to display only parts of its data, for example, only certain columns or certain rows fulfilling some criteria, like having a phone number from a certain area code. All this can be achieved with XSL style sheets.
Making HTML code from XML and XSL
We need a method which takes two strings, one XML string and one XSL string, and generates an HTML string.
We use the class
XPathDocument to hold our XML data. The XSL code is read into an object of class
XslTransform using its
Load method. The
XslTransform object is used with the
XPathDocument object to generate HTML code. This is done with its
OK, enough talk, let's see some code.
public string MakeHTML(string xml, string xsl)
StringReader xmlStringReader = new StringReader(xml);
XPathDocument xPathDocument = new XPathDocument(xmlStringReader);
StringReader xslStringReader = new StringReader(xsl);
XmlTextReader xslTextReader = new XmlTextReader(xslStringReader);
XslTransform xslTransform = new XslTransform();
xslTransform.Load(xslTextReader, null, GetType().Assembly.Evidence);
StringWriter htmlStringWriter = new StringWriter();
xslTransform.Transform(xPathDocument, null, htmlStringWriter, null);
string html = htmlStringWriter.ToString();
Wow! As you can see, we needed a lot of readers to just load the XML data and the XSL style sheet, before we could call the
Transform method. If we would be working with files instead, only a few lines of code would be necessary.
Opening Internet Explorer
Now when we have our HTML code, we need to display it in a web browser. Internet Explorer is available on any Windows machine and it has a decent API, so we will always use Internet Explorer to display our reports, instead of FireFox, I mean the user’s default browser.
We create a new instance of the Internet Explorer using the SHDocVw.dll component. Then we get hold of one of its many interfaces, the interface called
IWebBrowser2. Now we have created an Internet Explorer instance and can access it. We make the instance visible and open it. We will now start displaying our HTML code. For this, we need an empty webpage so we have something to update. We navigate (means browse) to a blank page, brought to you courtesy of the Internet Explorer. We can now access its document, through an interface called
mshtml.IHTMLDocument2. We write the HTML code and in order to get Internet Explorer to update its document and display our report, we need to close the document.
public void DisplayHTML(string html)
SHDocVw.InternetExplorer internetExplorer =
SHDocVw.IWebBrowser2 webBrowser = (SHDocVw.IWebBrowser2)internetExplorer;
webBrowser.Visible = true;
object noValue = System.Reflection.Missing.Value;
webBrowser.Navigate("about:blank", ref noValue,
ref noValue, ref noValue, ref noValue);
mshtml.IHTMLDocument2 htmlDoc =
internetExplorer.Document as mshtml.IHTMLDocument2;
To be able to use the above mentioned COM objects, we need to add MSHTM and SHDocVw to our references. See this blog entry for how to do so in case you don’t know the details: Injecting HTML code directly into an Internet Explorer.
The modal Format dialog generates the XSL style sheet and customizes it depending on user’s preferences.
The XML data is generated from the
Listview control by looping over each subitem and transforming it to XML data. If this would have been a real application, most likely the data displayed in the
Listview control would have come from some business object, a collection of some kind. All the .NET collection classes support XML serialization, so using XML as data format for our report is therefore a straightforward and quite natural representation for our project.
I'm a software developer from Sweden who got tired of snow and cold weather and moved to USA. I choose New York City, so I wouldn't totally miss out on snow and cold weather. I work on Wall Street with financial systems (not much else to do in this neighborhood). I primarily use Visual C++/MFC or C#/.NET as development tool.
The picture is of my wife and me in Cannes, France, drinking the most expensive Coke we ever had.