Introduction
Recently during the development of a consolidated report for a web
application we used XML/XSL processing to generate the report which is
basically a custom grid generated out of the XSL processing. The screenshot of
the user interface is given in the overview section.
The report was designed using a custom grid generated using the XSL from
the XML data. The report was basically showing consolidated data for daily, MTD
and yearly. The XML output contains data for daily, MTD and YTD for a given
trade date. So the problem was extracting the corresponding data from the XML
when the user selects Daily /MTD/Yearly in the UI.
As usual the initial thoughts were to use three XSL for processing
daily, monthly & yearly. But when looking forward, thoughts about
maintainability and repetition of the code made me to look for a more reliable
solution. Let’s see how we implemented the solution.
Overview
Not going into the details of how the grid was developed; just adhering
to the problem lets look at the brief of the requirements.
To make the understanding much better lets have a glance of the
reporting screen. The user selects the report type (value will be either
‘D’,’Y’,’M’) from the screen and click the apply button; on the basis the user
selection the XML data need to be extracted and processed.
For e.g. In the report screen the report header is one of the XML element
which needs to be extracted corresponding to the report type selected by the
user. When the user selects ‘Daily’ from the report type then XSL processor
needs to extract the XPATH ‘root/reportparameters/reportdescription/description/@view’
= ‘D’ from the XML.

XML Sample
Please find the sample XML below. The solution needs to extract the XML
data from the nodes for attribute value like ‘view’ from
‘root/reportparameters/reportdescription/description/@view’ for report header
corresponding to the report type.
The attribute have values like ‘D’, ‘M’, ‘Y’ which corresponds to daily,
MTD, yearly respectively.
Similarly for the report data, this needs to be
from ‘root/datarows/datarow/amounts/@aggregation’.

Solution
1
The easiest solution is to have three XSL where the attribute value
‘D’,’M’,’Y’ is hard coded. But on long run this becomes question for
maintainability and the same code is repeated over the three XSL. The snippet
of one of the three XSL is given below. The XML/XSL processing technique is
explained in the solution 2.
="1.0" ="iso-8859-1"
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<div class="controlname reportdesc" style="font-style: italic">
<xsl:for-each select ="root/reportparameters/reportdescription">
<xsl:value-of select="description[@view='D']"/>
</xsl:for-each>
</div>
<br/>
</xsl:template>
</xsl:stylesheet>
Solution 2
The best solution is to have a single XSL where parameter can be passed
from web application which can be done from client side or server side
depending on the requirement. The challenge will be how we can pass parameter
to XSL from client side processing and whether the same can be done from server
side too?
Will explain both the ways as we go.
Let’s quickly jump to the solution, not sure whether I have explained a
lot rather than coming to the solution.
XML/XSL processing from Client Side
The
XSL processing is done by creating Microsoft.XMLDOM
object to load the XML data. Similarly object to load XSLT need to be created from
FreeThreadedDOMDocument. The
transformation is done on the XSLT processor object created; this is done by
calling the transform method on the above object.
The
above process is preferred over the one where we can use "transformNode"
method of Microsoft.XMLDOM object to
process the XML since this one doesn’t allows to parameters in XSLT.
The
steps involved are:
1. var xml = new ActiveXObject("Microsoft.XMLDOM");
2. var xslt = new ActiveXObject("MSXML2.FreeThreadedDOMDocument");
3. xml.load("data.xml");
4. xslt.load("transformxsl.xsl");
5. var processor = new ActiveXObject("Msxml2.XSLTemplate");
6. processor.stylesheet = xslt;
7. var objXSLTProc = processor.createProcessor();
8. objXSLTProc.input = xml;
9. objXSLTProc.addParameter("reporttype", GetReportType());
10. objXSLTProc.transform();
11. document.getElementById("divReportGrid").innerHTML = objXSLTProc.output;
In the above
code line # 3 does the loading of
the XML; this can be done also by using a call to a separate ASPX page where
response type is ‘text/xml’.
Line # 9 does the actual parameter passing; the
objXSLTProc
object is defined with a parameter name ‘reporttype’. The value of the same is
retrieved using the JavaScript function GetReportType().
Finally the report is rendered using the XSL processor output to a DIV
tag.
Let’s have a look of the XSL (For
explanation it’s a sample from the original XML)
="1.0" ="iso-8859-1"
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name ="reporttype"></xsl:param>
<xsl:template match="/">
<div class="controlname reportdesc" style="font-style: italic">
<xsl:for-each select ="root/reportparameters/reportdescription">
<xsl:value-of select="description[@view=$reporttype]"/>
</xsl:for-each>
</div>
<br/>
</xsl:template>
</xsl:stylesheet>
In the above XSL a XSL param named ‘reporttype’ is defined. And the report header is processed using the XPATH for the attribute ‘view’ which is linked to the XSL param defined.
XML/XSL Processing from Server Side (C#)
The XML/XSL processing is done using the
XPathDocument
and applying parameter on the XsltArgumentList object. Finally the same is
transformed on the XPathDocument object using the XslCompiledTransform object.
After XSL processing the HTML output will be in the StringWriter object.
MemoryStream ms =
new MemoryStream(System.Text.Encoding.UTF8.GetBytes(XPathDocument document = new XPathDocument(ms);
XslCompiledTransform transform = new XslCompiledTransform();
transform.Load(Server.MapPath(@"/XSL/Sample.xsl"));
StringWriter sw = new StringWriter();
XsltArgumentList xslArg = new XsltArgumentList();
xslArg.AddParam("reporttype", "", reportTypeParam.ToString());
transform.Transform(document, xslArg, sw);
Solution
Implementation
Finally the
solution applied was client side XSL processing using a single XSL. The server
side XML/XSL processing was applied for generating an Excel report.
Summary
In the
article I tried to explain various ways by which XML/XSL processing with
parameter passing can be done and applied to various applications.