Introduction
In most cases, server controls are very useful in ASP.NET web applications since they have some valuable events (for example, click event, data binding event, data bound event, etc.) and many advance functionalities like state management, input validation, etc. In general, XSLT produces plain XML or HTML without any hassle, but if we want to create our ASP.NET server control by using XML and XSLT, then we should follow some procedures which will be described below.
XML has vast uses in web applications, and when we combine XML and XSLT, it shows its own strength and beauty which can speed up our application very much. One major benefit of using XML is column flexibility. Suppose there are two types of addresses in our application: home address and office address. This number can be increased or decreased anytime without changing much code. And using XSLT, we will not just create server controls, but also define their events which will work like a magic.
Requirements
I am assuming that the reader of this article has basic knowledge of XML, XSLT and ASP.NET.
Using the code
We will follow these steps to get things done:
- Prepare the XML document
- Prepare the XSLT document to transform the XML data
- Write the C# code to instantiate the controls and event handlers
Consider the following XML:
<root>
<Employee Id="1">
<Address Caption="Address">
<Home Caption="Home 1">
<Street Caption="Street 1" Type="Text">Road# 27, House# 13, Banani</Street>
<Street Caption="Street 2" Type="Text">
</Street>
<City Caption="City" Type="Text" Required="yes">Dhaka</City>
<Zip Caption="Zip" Type="Text">1213</Zip>
<Country Caption="Country" Type="CountryDDL">BD</Country>
</Home>
<Home Caption="Home 2">
<Street Caption="Street 1" Type="Text">Sector- 10</Street>
<Street Caption="Street 2" Type="Text">Uttara</Street>
<Street Caption="Street 3" Type="Text">
</Street>
<City Caption="City" Type="Text" Required="yes">Dhaka</City>
<Zip Caption="Zip" Type="Text">1230</Zip>
<Country Caption="Country" Type="CountryDDL">BD</Country>
</Home>
</Address>
</Employee>
<Employee Id="2">
<Address Caption="Address">
<Home Caption="Home 1">
<Street Caption="Street 1" Type="Text">J-13, Road 27</Street>
<Street Caption="Street 2" Type="Text">Banani</Street>
<City Caption="City" Type="Text">Dhaka</City>
<Zip Caption="Zip" Type="Text">1213</Zip>
<Country Caption="Country" Type="CountryDDL">BD</Country>
</Home>
<Home Caption="Home 2">
<Street Caption="Street 1" Type="Text">Michigan Avenue</Street>
<Street Caption="Street 2" Type="Text">Suite 2800</Street>
<Street Caption="Street 3" Type="Text">
</Street>
<City Caption="City" Type="Text">Chicago</City>
<Zip Caption="Zip" Type="Text">60601</Zip>
<Country Caption="Country" Type="CountryDDL">USA</Country>
</Home>
</Address>
</Employee>
</root>
We have to show the addresses like below:
Since there are multiple employee’s data in our XML document, we have to select the requested employee’s data among them. For this purpose, we have to create an argument list and need to pass the employee ID through the XSLT parameter.
XsltArgumentList xslArg = new XsltArgumentList();
xslArg.AddParam("employeeId", "", ddlEmployee.SelectedValue);
XPathDocument xdoc = new XPathDocument(Server.MapPath("Address.xml"));
XslCompiledTransform transform = new XslCompiledTransform();
transform.Load(Server.MapPath("DynamicControls.xslt"));
StringWriter sw = new StringWriter();
transform.Transform(xdoc, xslArg, sw);
And, we will receive the argument from XSLT like below:
<!---->
<xsl:param name="employeeId"/>
If we see look at the XML, then we will find that there is a ‘Caption
’ attribute in each node. This is the caption of each value while showing the output. On the other hand, to give input, sometimes it is better to show a dropdown list rather than a traditional textbox. For instance, when the user has to choose country name, it is more meaningful to show a country list rather than a textbox. To fulfill this purpose, we have a similar attribute named ‘type
’ in the XML nodes. And by inspecting this attribute, we can render the appropriate ASP.NET server control from XSLT.
<xsl:choose>
<xsl:when test="translate($varType,$up,$lo)='countryddl'">
<asp:DropDownList id="{concat('ddlCountry',$rowindex)}" runat="server"
DataTextField="Text" DataValueField="Value">
<asp:ListItem value="{.}">
<xsl:value-of select="."/>
</asp:ListItem>
</asp:DropDownList>
</xsl:when>
<xsl:otherwise>
<asp:TextBox ID="{$varId}" runat="server"
Text="{.}" width="205px" ></asp:TextBox>
<xsl:if test="translate($isRequired,$up,$lo)='yes'">
<asp:RequiredFieldValidator ErrorMessage="
Required Field" runat="server"
ControlToValidate="{$varId}" />
</xsl:if>
</xsl:otherwise>
</xsl:choose>
At last, we must declare a button to save the input data in XSLT:
<asp:Button ID="btnSaveAddress" runat="server" BackColor="White"
BorderColor="DeepSkyBlue" BorderStyle="Solid"
BorderWidth="1px" Font-Names="Tahoma"
Font-Size="10pt" Text="Save Data" />
Now, we have to set the event handler for this button from the code behind. The ParseControl
function will make our work very easy by parsing the XML string to an ASP.NET server control. To get a reference of newly created controls, we have to call the FindControl
method. As soon as we get the reference of the control, we can set the event handler for that control. One thing that is very important to know is that the event handler adding process should be after parsing the control. Because, before parsing, the control will not be available. Also, the parsing should be in the Page_Init
event so that the controls will be available in the rest of the page life cycle.
Control ctrl = Page.ParseControl(result);
phEmployeeAddress.Controls.Add(ctrl);
Button btnSaveAddress = (Button)phEmployeeAddress.FindControl("btnSaveAddress");
btnSaveAddress.Click += new EventHandler(btnSaveAddress_Click);
We have almost covered everything. The most interesting thing is, using XSLT, our ASPX page will become very simple and clear. Here is the full ASPX source:
<%@ Page Language="C#"
AutoEventWireup="true" CodeFile="Default.aspx.cs"
Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Dynamic ASP.net Controls Using Xslt</title>
</head>
<body>
<form id="form1" runat="server">
<div style="float: right; background-color: Yellow">
<asp:Label ID="lblMessage" runat="server"
Text="Label"></asp:Label>
</div>
<div>
<asp:Label ID="Label1" runat="server"
Text="Choose Employee"></asp:Label>
<asp:DropDownList ID="ddlEmployee"
runat="server" Width="128px">
<asp:ListItem Value="1">Ehsan</asp:ListItem>
<asp:ListItem Value="2">Ashraf</asp:ListItem>
</asp:DropDownList>
<asp:Button ID="btnLoadData" runat="server"
BackColor="White" BorderColor="DeepSkyBlue"
BorderStyle="Solid" BorderWidth="1px"
Font-Names="Tahoma" Font-Size="10pt"
Text="Load Data"
OnClick="btnLoadData_Click" /><br />
<br />
<asp:PlaceHolder ID="phEmployeeAddress"
runat="server"></asp:PlaceHolder>
</div>
</form>
</body>
</html>
All the XSLT controls will be extracted to the PlaceHolder
, and here is the entire XSLT used to render the HTML and server controls:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:asp="remove">
<xsl:output method="xml" indent="yes"
encoding="utf-8" omit-xml-declaration="yes"/>
-->
<xsl:param name="employeeId"/>
<xsl:template match="/root">
<xsl:for-each select="Employee">
<xsl:if test="@Id = $employeeId">
<table width="100%" border="0"
cellspacing="0" cellpadding="0"
bgcolor="#FFFFFF">
<tbody>
<tr>
<td>
<xsl:apply-templates select="Address">
-->
</xsl:apply-templates>
</td>
</tr>
<tr>
<td> </td>
</tr>
<tr>
<td align="right">
<span style="margin-right:20%">
<asp:Button ID="btnSaveAddress"
runat="server" BackColor="White"
BorderColor="DeepSkyBlue" BorderStyle="Solid"
BorderWidth="1px" Font-Names="Tahoma"
Font-Size="10pt" Text="Save Data" />
</span>
<span> </span>
</td>
</tr>
</tbody>
</table>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template name="HomeAddress"
match="/root/Employee/Address">
<table width="100%">
<tr>
<td height="30" colspan="2" align="left">
<strong>
<xsl:value-of select="@Caption"/>
</strong>
</td>
</tr>
<tr>
<td height="2" colspan="2"
align="left" bgcolor="#CCCC99"></td>
</tr>
<tr>
<td width="50%" height="30"
align="left" valign="top">
<table width="100%" border="0"
cellspacing="0" cellpadding="0">
<tr>
<td colspan="4" height="4"></td>
</tr>
<tr>
<xsl:for-each select="child::*">
<xsl:variable name="rowindex"
select="position()"></xsl:variable>
<td align="left" valign="top">
<table cellpadding="4">
<tr>
<td colspan="4" height="28"
align="left" valign="top">
<strong>
<xsl:value-of select="@Caption"/>
</strong>
</td>
</tr>
<xsl:for-each select="child::*">
<xsl:variable name="varType"
select="@Type"></xsl:variable>
<xsl:variable name="isRequired"
select="@Required"></xsl:variable>
<xsl:variable name="varId"
select="translate(concat(concat(concat(@Caption,'_'),
$rowindex),position()),' ','_')">
</xsl:variable>
<xsl:variable name="up"
select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:variable name="lo"
select="'abcdefghijklmnopqrstuvwxyz'"/>
<tr>
<td height="28" align="left" valign="top">
<xsl:value-of select="@Caption"/>
</td>
<td colspan="3" align="left"
valign="top" height="28">
<xsl:choose>
<xsl:when test="translate($varType,$up,$lo)='countryddl'">
<asp:DropDownList id="{concat('ddlCountry',$rowindex)}"
runat="server" DataTextField="Text"
DataValueField="Value">
<asp:ListItem value="{.}">
<xsl:value-of select="."/>
</asp:ListItem>
</asp:DropDownList>
</xsl:when>
<xsl:otherwise>
<asp:TextBox ID="{$varId}"
runat="server" Text="{.}"
width="205px" ></asp:TextBox>
<xsl:if test="translate($isRequired,$up,$lo)='yes'">
<asp:RequiredFieldValidator
ErrorMessage="Required Field" runat="server"
ControlToValidate="{$varId}" />
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</td>
</tr>
</xsl:for-each>
</table>
</td>
</xsl:for-each>
</tr>
</table>
</td>
</tr>
</table>
</xsl:template>
</xsl:stylesheet>
Summary
ASP.NET server controls are very powerful in web applications without any doubt, and by combining XML and XSLT with it, we can make web applications more powerful, easier, efficient, and re-usable. Also, by using XML and XSLT, the application UI script will look clean and will be easier to maintain. I hope this will be a great start for those who want to make their site more dynamic and structured using XML and XSLT with the great power of ASP.NET controls. Enjoy!