Advanced XSL Transformations With ASP.NET - The Magic of Compounding
(Page 5 of 7 )
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.
Next: The Magic of Compounding Demystified >>
More ASP.NET Articles
More By Harish Kamath