Advanced XSL Transformations With ASP.NET - Getting Feedback
(Page 3 of 7 )
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:

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

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.
Next: Code in Your Style Sheets >>
More ASP.NET Articles
More By Harish Kamath