Advanced XSL Transformations With ASP.NET

There are the beginners, the novices, and the newbies — and there are the pros. Today, we are going to help you to make that big transformation (pun intended) from the first group to the more prestigious second group — at least when it comes to XSL Transformations with ASP.NET!

A few weeks ago, we wrote an introductory article on XSL Transformations with the .NET platform. It gave you a quick overview of the “Xml” server control and the XslTransform() object – both of which allow us to transform XML documents using XSLT style sheets in ASP.NET.

Today, we will examine the more complex tasks that are possible using these technologies. So if you haven’t read the introductory article, we recommend that you do so immediately as it lays the foundation for today’s article. (Editor’s note: the introductory article is located here).

Before we proceed, we must also warn you that this article assumes that you are very comfortable with advanced XSLT concepts such defining variables, passing parameters, looping around nodes, and so forth. If these terms sound like Greek and Latin, we recommend that you read up on the XSLT tutorials listed at the end of this article.

And don’t forget to come back here, once you’re done!

{mospagebreak title=Passing the buck}

One of the interesting features of XSL Transformations is the ability to define input parameters in a style sheet. Then we can assign values to these parameters at run-time and selectively transform the associated XML document.

Consider the following “articles.xml” file:

<?xml version=”1.0″?>
<articles>
    <article id=”110″>
        <title>XSL Transformations with ASP.NET</title>
        <author>Harish R. Kamath</author>
        <category>ASP.NET</category>
        <abstract>Leverage on the built-in functionality available in ASP.NET to transform your XML documents using XSL Transformations!</abstract>
    </article>
    <article id=”109″>
        <title>Input Validation in ASP.NET</title>
        <author>Harish R. Kamath</author>
        <category>ASP.NET</category>
        <abstract>Prevent corrupt data from entering into your database – use built-in ASP.NET validation controls in your scripts.</abstract>
    </article>
    <article id=”108″>
        <title>Master the ASP.NET DataGrid Server Control</title>
        <author>Harish R. Kamath</author>
        <category>ASP.NET</category>
        <abstract>Learn how to use the powerful ASP.NET DataGrid server control to list data from a database table.</abstract>
    </article>
</articles>

A few weeks ago, we showed you how to transform this XML file in order to display a listing in the browser. However, wouldn’t it be great if we could just select a single article from this list?

This is where the ability to define input parameters in a XSLT style sheet is useful.

The above XML structure defines an attribute called “id” for each <article> element. We can use this “id” attribute to filter the required <article> at run time. This is analogous to the use of a primary key to retrieve a single row from a database table.

Here is an updated version of the earlier “articles.xsl” style sheet:

<?xml version=”1.0″?>
<xsl:stylesheet xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”
version=”1.0″>

    <xsl:param name=”id” />
    <xsl:template match=”articles”>
    <xsl:apply-templates select=”//article[@id=$id]”/>
    </xsl:template>

    <xsl:template match=”article”>
    <xsl:apply-templates select=”title”/>
    <xsl:apply-templates select=”author”/>
    <xsl:apply-templates select=”category”/>
    <xsl:apply-templates select=”abstract”/>
    </xsl:template>

    <xsl:template match=”title”>
        <H3>Article Title: <xsl:value-of select=”.” /></H3>
    </xsl:template>

    <xsl:template match=”author”>
        <H4>Author: <xsl:value-of select=”.” /></H4>
    </xsl:template>

    <xsl:template match=”category”>
        <H4>Category: <xsl:value-of select=”.” /></H4>
    </xsl:template>

    <xsl:template match=”abstract”>
        <H5>Abstract:</H5>
        <xsl:value-of select=”.” />
    </xsl:template>

</xsl:stylesheet>

The major change in this updated version is the introduction of the following code:

<%

      // snip

    <xsl:param name=”id” />
    <xsl:template match=”articles”>
    <xsl:apply-templates select=”//article[@id=$id]”/>
    </xsl:template>

    // snip

%>

There are two new XSLT concepts used here. The first concept is the definition of an input parameter (called “id”) for the style sheet using the <xsl:param> element, and the second is the use of an XPath expression. While the first concept is pretty self-explanatory, the use of an XPath expression allows us to select a particular node, i.e. a single <article> element from the “articles.xml” file.

So far, so good. But, how do you pass a value to the input parameter in the style sheet?

Frankly, this depends on the XSLT transformer in use. In our case, the XslTransform() object has the required provisions and  the following script shows you how:

<%@ Page Language=”C#” %> <%@ import Namespace=”System.Xml.Xsl” %> <%@ import Namespace=”System.Xml.XPath” %> <%@ import Namespace=”System.IO” %> <script runat=”server”>

void Page_Load() {

        // path to the XML and XSLT files
        string strXsltFile = Server.MapPath(“articles.xsl”);
        string strXmlFile = Server.MapPath(“articles.xml”);

        // create instance of XstTransform object
        XslTransform objXslTransform = new XslTransform();

        // load the XSLT style sheet
        objXslTransform.Load(strXsltFile);

        // create an instance of XPathDocument object
        XPathDocument objXmlFile = new XPathDocument(strXmlFile);

         // Create an instance of XsltArgumentList object
         XsltArgumentList objXslInputArgs = new XsltArgumentList();
         objXslInputArgs.AddParam(“id”,””,”110″);

        // create an instance of StringWriter object
        StringWriter objSWriter = new StringWriter();

        // transform the XML file
        objXslTransform.Transform(objXmlFile, objXslInputArgs, objSWriter);

        // display the output in the browser
        output.Text = objSWriter.ToString();

        // clean up memory
        objXmlFile = null;
        objXslTransform = null;
        objSWriter = null;

}
</SCRIPT>
<HTML>
<HEAD>
    <TITLE>ASPFree.com</TITLE>
    <BASEFONT face=”Arial” />
</HEAD>
<BODY>
    <asp:Label id=”output” runat=”server”></asp:Label>
</BODY>
</HTML>

 

Load this script in your browser to view the following output:

Advanced XSL Transformations in ASP.NET

Let us skip the mundane details and drill straight down to the snippet that matters:

<%

 // snip

 // create an instance of XsltArgumentList object
 XsltArgumentList objXslInputArgs = new XsltArgumentList();
      objXslInputArgs.AddParam(“id”,””,”110″);

 // snip

%>

Time to introduce one more object from the “System.Xml.Xsl” assembly: the XsltArgumentList() object. As the name suggests, it allows us to define a list of name-value pairs that can be sent as an input argument to the style sheet.

Adding a new name-value pair is as simple as invoking the AddParam() method. This method takes three parameters: the name of parameter in the style sheet file, a namespace URI (if any) and finally, the value itself. In our example, we add a parameter with the name “id” and assign a value to it (hard-coded for the moment).

Now, we need to pass this list to the underlying style sheet. Readers with a sharp memory will recall that we always passed a NULL value (for the second parameter) whenever we invoked the Transform() method of the XslTransform() object. The reason was simple: no input parameter defined, no value passed.

This is not true any longer. The following code snippet show us how to pass the objXslInputArgs() object, instantiated above, to the Transform() method — which, in turn, passes it to the style sheet.

<%

// snip

// transform the XML file
objXslTransform.Transform(objXmlFile, objXslInputArgs, objSWriter);

// snip

%>

The rest of the code is routine stuff. We retrieve the output of the XSL transformation in the form of the objSWriter() object and display the resultant HTML code in the “output” label server control.

{mospagebreak title=Getting Feedback}

Most websites (including ASPFree.com) allow visitors to post feedback and ratings that are then displayed on the website. The next example shows us how we can do the same using a simple ASP.NET script, and the best part is that all the information is stored in a single XML file.

Sounds interesting? You bet it does!

First, we update “articles.xml” to include the comments and ratings posted by the readers.

<?xml version=”1.0″?>
<articles>
    <article id=”110″>
        <title>XSL Transformations with ASP.NET</title>
        <author>Harish R. Kamath</author>
        <category>ASP.NET</category>
        <abstract>Leverage on the built-in functionality available in ASP.NET to transform your XML documents using XSL Transformations!</abstract>
        <reviews>
            <review id=”1002″>
                <username>john_king</username>
                <rating>5</rating>
                <comments>Great article… Covering all concepts very well!!!</comments>
            </review>
            <review id=”1023″>
                <username>michael</username>
                <rating>4</rating>
                <comments>Author has done a good job. But it could have been more comprehensive…</comments>
            </review>
            <review id=”1023″>
                <username>john</username>
                <rating>1</rating>
                <comments>Help!!! I cannot get the last example to work… What is wrong?</comments>
            </review>
        </reviews>
    </article>
    <article id=”109″>
        <title>Input Validation in ASP.NET</title>
        <author>Harish R. Kamath</author>
        <category>ASP.NET</category>
        <abstract>Prevent corrupt data from entering into your database – use built-in ASP.NET validation controls in your scripts.</abstract>
        <reviews>
            <review id=”1023″>
                <username>rajesh</username>
                <rating>3</rating>
                <comments>Good job…</comments>
            </review>
        </reviews>
    </article>
    <article id=”108″>
        <title>Master the ASP.NET DataGrid Server Control</title>
        <author>Harish R. Kamath</author>
        <category>ASP.NET</category>
        <abstract>Learn all about the powerful ASP.NET Data Grid object…</abstract>
        <reviews>
            <review id=”1002″>
                <username>kingston</username>
                <rating>5</rating>
                <comments>Well researched…</comments>
            </review>
            <review id=”1023″>
                <username>michael</username>
                <rating>4</rating>
                <comments>Keep writing more articles like this… and I will come back more often.</comments>
            </review>
            <review id=”1023″>
                <username>john</username>
                <rating>1</rating>
                <comments>Could not understand this concept… please explain it better!!!</comments>
            </review>
        </reviews>
    </article>
</articles>

Look closely and you’ll notice that we have added a <reviews> element for every <article>. Each <reviews> element, in turn, consists of a set of <review> elements, each of which encloses a <username>, a <rating> and a <comments> element.

Here, we’ll require two style sheets. The first one helps to display the article listing, and the second one to display the ratings and comments for the selected article.

Here is the first style sheet (say “articles_list.xsl”):

<xsl:stylesheet version=”1.0″ xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”>

<xsl:template match=”/”>
<HTML>
<HEAD>
    <TITLE>ASPFree.com</TITLE>
    <BASEFONT face=”Arial” />
</HEAD>
<BODY>
 <xsl:apply-templates select=”articles” />
</BODY>
</HTML>
</xsl:template>

<xsl:template match=”articles”>
 <H3>List of Articles By Harish Kamath</H3>
 <OL><xsl:apply-templates select=”article”/></OL> </xsl:template>


<xsl:template match=”article”>
 <xsl:apply-templates select=”title”/>
</xsl:template>

<xsl:template match=”title”>
    <LI><xsl:value-of select=”.” /> –
            <xsl:element name=”A”>
                <xsl:attribute name=”href”>articles_02.aspx?id=<xsl:value-of
select=”../@id”/></xsl:attribute>
Reviews
            </xsl:element>
        <BR /><BR />
    </LI>
</xsl:template>

</xsl:stylesheet>

Here we would like to highlight the use of <xsl:element> and <xsl:attribute> in order to generate an anchor <A> element in the resultant HTML output.

Here is the second style sheet (say “articles_reviews.xsl”):

<?xml version=”1.0″?>
<xsl:stylesheet xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”
version=”1.0″>

    <xsl:param name=”id” />
    <xsl:template match=”articles”>
    <xsl:apply-templates select=”//article[@id=$id]”/>
    </xsl:template>

    <xsl:template match=”article”>
    <xsl:apply-templates select=”title”/>
    <xsl:apply-templates select=”author”/>
    <xsl:apply-templates select=”category”/>
    <xsl:apply-templates select=”abstract”/>
       <xsl:apply-templates select=”reviews”/>
    </xsl:template>

    <xsl:template match=”title”>
        <H3>Article Title: <xsl:value-of select=”.” /></H3>
    </xsl:template>

    <xsl:template match=”author”>
        <H4>Author: <xsl:value-of select=”.” /></H4>
    </xsl:template>

    <xsl:template match=”category”>
        <H4>Category: <xsl:value-of select=”.” /></H4>
    </xsl:template>

    <xsl:template match=”abstract”>
        <H5>Abstract:</H5>
        <xsl:value-of select=”.” />
    </xsl:template>

    <xsl:template match=”reviews”>
        <H5>Reviews:</H5>
        <xsl:for-each select=”review”>
         <H5>
          User: <xsl:value-of select=”username”/><BR />
          Rating: <xsl:value-of select=”rating” /><BR />
             Comments: <I><xsl:value-of select=”comments”/></I>
         </H5>
  </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

Once again, we have defined an input parameter using the <xsl:param> element and an XPath expression that allows us to select a particular <article> node. Further down, we have used the <xsl:for-each> loop construct to iterate over the list of <review> elements associated with each <article> in order to render them in the output.

Finally, here is the ASP.NET script (say “articles.aspx”):

<%@ Page Language=”C#” %>
<%@ import Namespace=”System.Xml.Xsl” %>
<%@ import Namespace=”System.Xml.XPath” %>
<%@ import Namespace=”System.IO” %>
<HTML>
<HEAD>
    <TITLE>ASPFree.com</TITLE>
    <BASEFONT face=”Arial” />
   <SCRIPT runat=”server”>

 void Page_Load(){

  // define local variables
  string strXslTFile = “”;

  // path to the XML file
  string strXmlFile = Server.MapPath(“articles.xml”);

  // instantiate required objects
  XslTransform objXslTransform = new XslTransform();
  XPathDocument objXmlFile = new XPathDocument(strXmlFile);
  StringWriter objSWriter = new StringWriter();

  // check if id is sent as parameter
  if(Request.QueryString[“id”] == null) {

   // display article list

   // path to the XSLT file
   strXslTFile = Server.MapPath(“articles_list.xsl”);

   // load the XSLT style sheet
   objXslTransform.Load(strXslTFile);

   // transform he XML file
   objXslTransform.Transform(objXmlFile, null, objSWriter);

  } else {

   // display details of selected article

   // path to the XSLT file
   strXslTFile = Server.MapPath(“articles_reviews.xsl”);

   // load the XSLT style sheet
   objXslTransform.Load(strXslTFile);

   // Create an instance of XsltArgumentList object
   XsltArgumentList objXslInputArgs = new XsltArgumentList();
   objXslInputArgs.AddParam(“id”, “”, Request.QueryString[“id”]);

   // transform the XML file
   objXslTransform.Transform(objXmlFile, objXslInputArgs, objSWriter);

   // clean up memory
   objXslInputArgs = null;
  }

  // display the output in the browser
  output.Text = objSWriter.ToString();

  // clean up memory
  objXmlFile = null;
  objXslTransform = null;
  objSWriter = null;
 }
</SCRIPT>
</HEAD>
<BODY>
    <asp:Label id=”output” runat=”server”></asp:Label>
</BODY>
</HTML>

 

Load this example in your browser to view the listing:

Advanced XSL Transformations in ASP.NET

Click on “Review” link displayed alongside the title of any one article to view the following output:

Advanced XSL Transformations in ASP.NET

There are two distinct actions that occur in the above script: the first displays the listing of articles and the second displays of the details of a selected article.

But how do we decide which action to perform? It’s simple — review the following snippet:

<%

 // snip

 // define local variables
 string strXslTFile = “”;

 // path to the XML file
 string strXmlFile = Server.MapPath(“articles.xml”);

 // instantiate required objects
 XslTransform objXslTransform = new XslTransform();
 XPathDocument objXmlFile = new XPathDocument(strXmlFile);
 StringWriter objSWriter = new StringWriter();

// check if id is sent as parameter
 if(Request.QueryString[“id”] == null) {

  // display article list
  // snip

 } else {

  // display details of selected article
// snip
}

// snip
%>

The script does a simple check to see if we have passed an “id” parameter in the query string. If there is no “id” present, it displays the listing and if there is one, it displays the details.

When we load the script without passing any “id” value, the following code snippet gets into the act.

<%

 // snip

 // check if id is sent as parameter
 if(Request.QueryString[“id”] == null) {

  // display article list

  // path to the XSLT file
  strXslTFile = Server.MapPath(“articles_list.xsl”);

  // load the XSLT style sheet
  objXslTransform.Load(strXslTFile);

  // transform he XML file
  objXslTransform.Transform(objXmlFile, null, objSWriter);

 } else {

  // display details of selected article
  // snip
}

// snip
%>

When we click on any one “Reviews” link, the page reloads with an “id” value in the query string. This time around the “else” block of our “if-else” statement is activated, and we load the second style sheet.

<%

 // snip

 // check if id is sent as parameter
 if(Request.QueryString[“id”] == null) {

  // display article list
  // snip

 } else {

  // display details of selected article

  // path to the XSLT file
  strXslTFile = Server.MapPath(“articles_reviews.xsl”);

  // load the XSLT style sheet
  objXslTransform.Load(strXslTFile);

  // Create an instance of XsltArgumentList object
  XsltArgumentList objXslInputArgs = new XsltArgumentList();
  objXslInputArgs.AddParam(“id”, “”, Request.QueryString[“id”]);

  // transform the XML file
  objXslTransform.Transform(objXmlFile, objXslInputArgs, objSWriter);

  // clean up memory
  objXslInputArgs = null;
}

// snip
%>

Here, we instantiated the XsltArgumentList() object and added the “id” parameter along with the value retrieved from the query string. Next, we passed this list to the XslTransform() object using the Transform() method, which in turn, passes it to our “articles_reviews.xsl” file. The XPath expression in the style sheet selects the appropriate <article> element and the <xsl:apply-templates> renders the selected node with the pre-defined template.

The end result: a neat little display of the details of the selected article along with the ratings and comments posted by readers.

{mospagebreak title=Code in Your Style Sheets}

Microsoft, being Microsoft, is known to add its own little tweaks (they call them enhancements) to the official specifications, and it is no different when it comes to XSL Transformations.

Why, you may ask?

Take a quick look at all style sheets listed so far and you will notice they consist of elements and more elements. This elements-only policy of the W3C for XML-related technologies has been implemented so strictly that even core programming constructs such as loops and conditional statements are implemented using XSL-specific elements such as <xsl:for-each> and <xsl:choose>.

While this makes life easy for folks with a non-technical background, it can get on the nerves of hardcore programmers who swear by their “if” statements and “for” loops. This is where the custom <msxsl:script> element, introduced by Microsoft for use in XSLT style sheets, comes in handy.

Consider the following example that adds and subtracts two numbers by invoking custom C# functions defined in the XSLT style sheet (say “calculator.xsl”) using the <msxsl:script> element.

<xsl:stylesheet version=”1.0″ xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”
xmlns:msxsl=”urn:schemas-microsoft-com:xslt”
xmlns:calculator=”urn:the-calculator”>

 <msxsl:script language=”C#” implements-prefix=”calculator”>

  <![CDATA[

   public double sum(double dblNumber1, double dblNumber2){
    return dblNumber1 + dblNumber2;
   }

   public double difference(double dblNumber1, double dblNumber2){
    return dblNumber1 – dblNumber2;
   }


  ]]>
 </msxsl:script>
 <xsl:template match=”input”>
  <xsl:variable name=”number1″ select=”number1″ />
  <xsl:variable name=”number2″ select=”number2″ />
  <xsl:element name=”output”>
   <xsl:copy-of select=”number1″ />
   <xsl:copy-of select=”number2″ />
   <xsl:element name=”sum”>
    <xsl:value-of select=”calculator:sum($number1, $number2)” />
   </xsl:element>
   <xsl:element name=”difference”>
    <xsl:value-of select=”calculator:difference($number1, $number2)” />
   </xsl:element>
    </xsl:element>
 </xsl:template>
</xsl:stylesheet>

Before we get into the nitty gritty on how this new <msxsl:script> element works,  let us review the associated XML file (say “input.xml”).

<?xml version=’1.0′?>
<input>
  <number1>5</number1>
  <number2>2</number2>
</input>

Let’s also review the ASP.NET script (say “calculator.aspx”).

<%@ Page Language=”C#” Debug=”true” %>
<%@ import Namespace=”System.IO” %>
<%@ import Namespace=”System.Xml” %>
<%@ import Namespace=”System.Xml.Xsl” %>
<%@ import Namespace=”System.Xml.XPath” %>
<script runat=”server”>

    void Page_Load()
    {

// define some variables
 string strXsltFile = Server.MapPath(“calculator.xsl”);
        string strInputXmlFile = Server.MapPath(“input.xml”);
         string strOutputXmlFile = Server.MapPath(“output.xml”);

         // create instance of XslTransform object
         XslTransform objXslTransform = new XslTransform();

 // load the XSLT style sheet
 objXslTransform.Load(strXsltFile);

     // transform the input XML file
     // and store result in output XML file
     objXslTransform.Transform(strInputXmlFile, strOutputXmlFile);

 // output message
 output.Text = strOutputXmlFile + ” file created successfully.”;

         // clean up memory
         objXslTransform = null;
    }
</SCRIPT>
<HTML>
<HEAD>
    <TITLE>Mathematics using XSLT style sheets</TITLE>
    <BASEFONT face=”Arial” />
</HEAD>
<BODY>
 <asp:Label id=”output” runat=”server”></asp:Label>
</BODY>
</HTML>

The XML file lists two numbers that we wish to add and subtract while the ASP.NET script contains routine code to publish the transformed output.

For the sake of completeness, this is output that you will view in the browser, when you load the script:

Advanced XSL Transformations in ASP.NET

Take a quick peek at the newly created output XML file:

Advanced XSL Transformations in ASP.NET

Now, let us shift our focus to the XSL style sheet that makes all this possible:

For starters, we have added some new namespace definitions to the root <xsl:stylesheet> element:

<xsl:stylesheet version=”1.0″ xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”
xmlns:msxsl=”urn:schemas-microsoft-com:xslt”
xmlns:calculator=”urn:the-calculator”>

// snip

</xsl:stylesheet>

You should be familiar with the first namespace definition, as it is the default namespace for all XSL style sheets. The second namespace, i.e. “xmlns:msxsl=”urn:schemas-microsoft-com:xslt” represents the Microsoft-defined namespace for the “msxsl” prefix, and the third — xmlns:calculator=”urn:the-calculator” — is the definition of our custom “calculator” namespace prefix. This third namespace definition is required to invoke the C# functions, defined later in the style sheet. More on this later.

Next, we have the definitions of the custom C# functions:

<%

// snip

<msxsl:script language=”C#” implements-prefix=”calculator”>

<![CDATA[

  public double sum(double dblNumber1, double dblNumber2){
   return dblNumber1 + dblNumber2;
  }

  public double difference(double dblNumber1, double dblNumber2){
   return dblNumber1 – dblNumber2;
  }
 ]]>
</msxsl:script>

// snip

%>

Within the <msxsl:script> element, we need to define a value for the “implements-prefix” attribute. This stores the name of the namespace prefix defined in the root <xsl:stylesheet> element. We also must specify the name of the .NET language used within the <msxsl:script> block using the “language” attribute.

Next, we have the definitions of our custom “sum” and “difference” functions within a CDATA section. This ensures that the XML parser does not balk when it encounters this section of the style sheet. After all, the XSLT style sheet needs to be a valid XML document, in keeping with W3C guidelines.

Finally, the XSLT code that invokes our custom function is in the following code snippet:

<%

 // snip

 <xsl:template match=”input”>
  <xsl:variable name=”number1″ select=”number1″ />
  <xsl:variable name=”number2″ select=”number2″ />
  <xsl:element name=”output”>
   <xsl:copy-of select=”number1″ />
   <xsl:copy-of select=”number2″ />
   <xsl:element name=”sum”>
    <xsl:value-of select=”calculator:sum($number1, $number2)” />
   </xsl:element>
   <xsl:element name=”difference”>
    <xsl:value-of select=”calculator:difference($number1, $number2)” />
   </xsl:element>
    </xsl:element>
 </xsl:template>

 // snip

%>

Once we match the <input> element from the XML file, we define two XSLT variables — number1 and number2 — to store the two numbers. Next, we create a new “output” element and create copies of the two <input> elements using the <xsl:copy-of> element. Then we invoke the “sum” and “difference” functions and enclose the results within two new custom elements,  <sum> and <difference>, respectively.

Note the use of the “calculate” namespace prefix to ensure that we invoke the correct C# function.

The “calculator.aspx” script contains routine code and you’ll agree with us — after all, you are a pro — that it deserves no further explanation.

Now that we have demonstrated the <msxsl:script> element,  we safely conclude that hardcore programmers will be satisfied with its introduction, since it allows them to use .NET languages rather than XSL Transformation elements to perform complex calculations.

The next section uses one such situation, and shows how this <msxsl:script> element makes life easy for us!

Intrigued? Read on.

{mospagebreak title=The Magic of Compounding}

Question: What is “compounding” ?

Answer: The term “compounding” — according to Dictionary.com — is a methodology that “computes interest on the principal and accrued interest” for a Certificate of Deposit (CD) opened at your friendly neighborhood bank.

For example, a CD for an amount US$1000 at 10% per annum for three years and no interest compounding is worth US$1300 when the CD matures. Assume that interest is compounded annually. Now, the same CD is worth US$1331 at maturity. No points for guessing which option gives you higher returns.

But what has all this to do with XSL Transformations?

Nothing. Just that we will use this concept as the basis for one final comprehensive example. This example will display a form that allows the user to enter a principal amount, the interest rate and the number of years for a deposit. On hitting the “Calculate” button, the following screen will display a ready-reckoner that lists the returns for different compounding terms. This demonstrates the real “magic of compounding.”

First, we have the ASP.NET script – “interest_calculator.aspx”:

<%@ Page Language=”C#” %>
<%@ import Namespace=”System.Xml.Xsl” %>
<%@ import Namespace=”System.Xml.XPath” %>
<%@ import Namespace=”System.IO” %>
<HTML>
<HEAD>
<TITLE>The Magic Of Compounding…</TITLE>
<SCRIPT language=”C#” runat=server>

void Submit_Form(object source, EventArgs args) {

    if (IsValid) {

  // all values are valid
  // proceed to display ready-reckoner

  // make the input form disappear
  // and the output label visible
     pnlInputForm.Visible = false;
  pnlOutput.Visible = true;

  // define some variables
  string strXsltFile = Server.MapPath(“interest_calculator.xsl”);
         string strXmlFile = Server.MapPath(“coumpounding_terms.xml”);

  // create instance of required objects
         MemoryStream objXmlStream = new MemoryStream();
       XslTransform objXslTransform = new XslTransform();
       XPathDocument objXmlFile = new XPathDocument(strXmlFile);

  // load the XSLT style sheet
  objXslTransform.Load(strXsltFile);

  // create an instance of XsltArgumentList object
  XsltArgumentList objXSLInputArgs = new XsltArgumentList();
  objXSLInputArgs.AddParam(“principal”,””,txtPrincipalAmt.Text);
  objXSLInputArgs.AddParam(“interest”,””,txtInterestRate.Text);
  objXSLInputArgs.AddParam(“years”,””,txtYears.Text);

      // transform the input XML file
      // and store result in a stream
      objXslTransform.Transform(objXmlFile, objXSLInputArgs, objXmlStream);

  // reset the position to the stream
  // to the beginning
  objXmlStream.Position = 0;

  // load the transformed XML in the MemoryStream object
  // into the XPathDocument object
  XPathDocument objTransformedXml = new XPathDocument(objXmlStream);

  // flush the memory stream as it is no longer required
  objXmlStream.Flush();
  objXmlStream.Close();

  // create an instance of StringWriter object
      // to store result of final transformation
      StringWriter objSWriter = new StringWriter();

  // XSL style sheet to format output of second transform
  string strXSLTFileOutput = Server.MapPath(“interest_calculator_output.xsl”);

  // load the XSLT style sheet
  objXslTransform.Load(strXSLTFileOutput);

      // transform the XML stream
      objXslTransform.Transform(objTransformedXml, null, objSWriter);

  // display output
  output.Text = objSWriter.ToString();

  // clean up memory
          objXmlFile = null;
  objTransformedXml = null;
         objXslTransform = null;
         objSWriter = null;

 }

}
</SCRIPT>
<BASEFONT face=”Arial”>
</HEAD>
<BODY>

<P><asp:Label id=”header” runat=”server” text=”The Magic Of Compounding” style=”font-weight:bold;font-size:18px;”/></P>

<asp:Panel id=”pnlOutput” runat=”server” visible = “true”>
 <P><asp:label id=”output” runat=”server” text=”” /></P> </asp:Panel>

<asp:Panel id=”pnlInputForm” runat=”server” visible = “true”>

<FORM runat=”server” method=”POST” >

<!– Principal Amount –>

<asp:Label id=”lblPrincipalAmt” runat=”server” text=”Principal Amount (in
USD): ” />
<asp:TextBox id=”txtPrincipalAmt” runat=”server” />

<asp:RequiredFieldValidator id=”ctlPrincipalAmtRFV” ControlToValidate=”txtPrincipalAmt” ErrorMessage=”Please enter the Principal Amount.” runat=”server” display=”dynamic” EnableClientScript=”true”/>

<asp:RangeValidator id=”ctlvalPrincipalAmtRV” ControlToValidate=”txtPrincipalAmt” ErrorMessage=”Please enter a amount between USD 1000 and USD 10000.” Type=”Double” MinimumValue=”1000″ MaximumValue=”10000″  runat=”server” Display=”dynamic”/> <BR /><BR />

<!– Interest Rate –>
<asp:Label id=”lblInterestRate” runat=”server” text=”Interest Rate: ” /> <asp:TextBox id=”txtInterestRate” runat=”server” />%

<asp:RequiredFieldValidator id=”ctlInterestRateRFV” ControlToValidate=”txtInterestRate” ErrorMessage=”Please enter the Interest Rate.” runat=”server” display=”dynamic” EnableClientScript=”true”/>

<asp:RangeValidator id=”ctlvalInterestRateRV” ControlToValidate=”txtInterestRate” ErrorMessage=”Please enter a number between 2 and 10.” Type=”Double” MinimumValue=”2″ MaximumValue=”10″ runat=”server” Display=”dynamic”/>

<BR/><BR />

<!– Number of Years –>

<asp:Label id=”lblYears” runat=”server” text=”Number of Years (for Deposit): ” /> <asp:TextBox id=”txtYears” runat=”server” />

<asp:RequiredFieldValidator id=”ctlYearsRFV” ControlToValidate=”txtYears” ErrorMessage=”Please enter the Number of Years.” runat=”server” display=”dynamic” EnableClientScript=”true”/>

<asp:RangeValidator id=”ctlvalYearsRV” ControlToValidate=”txtYears” ErrorMessage=”Please enter a number between 1 and 5.” Type=”Integer” MinimumValue=”1″ MaximumValue=”5″  runat=”server” Display=”dynamic”/>

<BR /> <BR />

<asp:Button OnClick=”Submit_Form” Text=”Calculate” runat=”server” />

</FORM>
</asp:Panel>

</BODY>
</HTML>

Next, we have an XML file (say “compounding_terms.xml”) that stores the different compounding terms:

<?xml version=’1.0′?>
<terms>
  <term>1</term>
  <term>2</term>
  <term>4</term>
  <term>6</term>
  <term>12</term>
</terms>

The interest is to be compounded annually if the value of compounding term is 1, semi-annually if the value is 2, quarterly if the value 4 and so on.

In this example, we perform two XSLT transformations back-to-back: the XML output of the first transformation is used as an input to the second transformation. This process is commonly referred to as “pipelining.”

The first style sheet (say “interest_calculator.xsl”) contains the definition of a custom C# function called calcCompundedAmount() and iterates over the different compounding terms in the XML file to calculate the maturity value for each term.

<xsl:stylesheet version=”1.0″ xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”
xmlns:msxsl=”urn:schemas-microsoft-com:xslt”
xmlns:calculator=”urn:the-calculator”>

 <msxsl:script language=”C#” implements-prefix=”calculator”>

  <![CDATA[

   public double calcCompundedAmount(double dblPrinicipal, double dblInterestRate, double intYears, double intCompoundingTerm){

     double dblCompoundedAmount = 0;

     dblCompoundedAmount = dblPrinicipal * (Math.Pow((1 + (dblInterestRate/(100 * intCompoundingTerm))), intYears * intCompoundingTerm));

     return Math.Round(dblCompoundedAmount, 2);

   }


  ]]>
 </msxsl:script>

    <xsl:param name=”principal” />
    <xsl:param name=”interest” />
    <xsl:param name=”years” />

 <xsl:template match=”terms”>
  <xsl:element name=”output”>
   <xsl:element name=”principal”>
    <xsl:value-of select=”$principal” />
   </xsl:element>
   <BR />
   <xsl:element name=”interest”>
    <xsl:value-of select=”$interest” />
   </xsl:element>
   <BR />
   <xsl:element name=”years”>
    <xsl:value-of select=”$years” />
   </xsl:element>
   <BR />
   <xsl:for-each select=”term”>
    <xsl:variable name=”term” select=”.” />
    <xsl:element name=”compoundedvalue”>
     <xsl:attribute name=”term”>
      <xsl:value-of select=”.” />
     </xsl:attribute>
     <xsl:value-of select=”calculator:calcCompundedAmount($principal,
$interest, $years, $term)” />
    </xsl:element>
    <BR />
   </xsl:for-each>
  </xsl:element>
 </xsl:template>
</xsl:stylesheet>

The second style sheet (say “interest_calculator_output.xsl”) contains routine code to render the final HTML output.

<?xml version=”1.0″?>
<xsl:stylesheet xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”
version=”1.0″>
 <xsl:template match=”output”>
  <P>Principal: USD <xsl:value-of select=”principal” /></P>
  <P>Interest Rate: <xsl:value-of select=”interest” />%</P>
  <P>Number of Years: <xsl:value-of select=”years” /></P>
  <HR />
  <P style=”font-weight:bold;font-size:16px;”>Final Amount</P>
  <xsl:for-each select=”compoundedvalue”>
   <P>Amount if Interest is compounded <xsl:value-of select=”@term” />
time(s) a year: USD <xsl:value-of select=”.” /></P>
  </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

While the above code listings do look overwhelming at first glance, be assured that the explanations in the following section will help clear all your doubts.

{mospagebreak title=The Magic of Compounding Demystified}

First, we have our “interest_calculator.aspx” ASP.NET script that displays a neat little form (as shown below) when first loaded in the browser. This Web form allows the user to enter the principal amount of the deposit, the interest rate offered and the number of years for which the amount will be deposited.

Advanced XSL Transformations in ASP.NET

As the user enters the required values in the form, the different ASP.NET Field Validator controls check if the values entered in the text fields are valid. If not, appropriate error messages are displayed. Here is a sample output if a user enters incorrect values:

Advanced XSL Transformations in ASP.NET

You can learn more about how to use these ASP.NET Field Validator server controls here: https://www.aspfree.com/c/a/ASP.NET/Input-Validation-With-ASP.NET-1/

When the user hits the “Calculate” button, the “OnClick” event associated with the button is fired and the ASP.NET script invokes our custom Submit_Form() function.

This Submit_Form() function — once again — checks if all the values entered in the form are valid. This is a quick server-side check made by checking the state of the “IsValid” flag. If there are no errors, it makes the “pnlInputForm” Panel control (displaying the Web form) disappear and the “pnlOutput” Panel control (enclosing a label control) visible.

Next, we proceed to carry out the first transformation by loading the “compounding_terms.xml” file and the “interest_calculator.xsl” file in XPathDocument() and XslTransform() objects respectively. Note that we have created a MemoryStream() object to store the XML output of this transformation.

Since the first style sheet require three input parameters — corresponding to the values entered on the Web form — we proceed to create an instance of the XsltArgumentList() object and add the required parameters (and values from the Text server controls) using the AddParam() method.

Next, we invoke the Transform() method to complete the first transformation. Here we use the custom calcCompundedAmount() function enclosed within the <msxsl:script> element (in the “interest_calculator.xsl” style sheet) to calculate the final value for each compounding term.

Here is a quick look at this function:

<%

// snip

<msxsl:script language=”C#” implements-prefix=”calculator”>

<![CDATA[

 public double calcCompundedAmount(double dblPrinicipal, double dblInterestRate, double intYears, double intCompoundingTerm){

 double dblCompoundedAmount = 0;

 dblCompoundedAmount = dblPrinicipal * (Math.Pow((1 + (dblInterestRate/(100
* intCompoundingTerm))), intYears * intCompoundingTerm));

return Math.Round(dblCompoundedAmount, 2);

}
]]>
</msxsl:script>

// snip

%>

The above formula (to calculate the compound interest) looks daunting, but it does the required job — take our word for it!

The following XML is generated as the output of the first transformation. Note that this output is never visible to the end user.

<?xml version=”1.0″ encoding=”utf-8″?>
<output>
<principal>1000</principal>
<interest>10</interest>
<years>3</years>
<compoundedvalue term=”1″>1331</compoundedvalue> <compoundedvalue term=”2″>1340.1</compoundedvalue> <compoundedvalue term=”4″>1344.89</compoundedvalue>
<compoundedvalue term=”6″>1346.53</compoundedvalue>
<compoundedvalue term=”12″>1348.18</compoundedvalue>
</output>

Instead, we proceed to instantiate a new XPathDocument() object using the MemoryStream() object and transform this XML data using the “interest_calculator_output.xsl” style sheet.

The end result is a neat display of data in a user-friendly manner, as shown below.

Advanced XSL Transformations in ASP.NET

Just a little warning before we close: it is required to reset the position of MemoryStream() to 0 before we pass it as an input of the second transformation; otherwise the .NET compile returns an error message stating the “root element cannot be found” and the script stops execution.

Now that we have demonstrated the “magic of compounding” using some powerful ASP.NET scripting and nifty XSL Transformations, it’s time to tell your neighborhood bank manager that you too want to enjoy this magic with your money!

{mospagebreak title=Conclusion}

That’s about it for today. Let us quickly review the concepts introduced in this article. First, we demonstrated the use of XPath expressions to filter XML data and followed it with an example that shows you how to use the XsltArgumentList() object to pass name-value parameter to an underlying style sheet.

Subsequently, we showed how to use the custom <msxsl:script> element to define custom functions written in our favorite .NET language (i.e. C#) in an XSLT style sheet and how you can invoke them in your style sheets.

The final example, building on the all concepts that we have mastered so far, demonstrated how you can conveniently pipeline the output of one XSL Transformation to another using the MemoryStream() object.

Earlier, we promised to list a set of URLs for XSL Transformations tutorials on the Internet. Here it is:

XSLT tutorial at W3Schools: http://www.w3schools.com/xsl/
default.asp

What is XSLT? at XML.com: http://www.xml.com/pub/a/2000/08/holman/

XSLT & XPath Tutorial at TopXML.com: http://www.vbxml.com/xsl/tutorials/intro/default.asp

XSLT Tutorial at Zvon.org: http://www.zvon.org/xxl/XSLTutorial/Output/index.html

XSLT Tutorial at CodeGuru.com: http://www.codeguru.com/Csharp/Csharp/cs_data/xml/
article.php/c7801/

This brings us to end of this article. Till next time, take care.

Note: All examples in this article have been tested on Windows 2000 Server with ASP.NET version 1.1 . Examples are illustrative only, and are not meant for a production environment. YMMV!

[gp-comments width="770" linklove="off" ]