A common way of using XML in ASP websites is to format dynamic information. In this article Eric shows us how to create a survey application using ASP.Net and XML.ASP.NET has made website development easier with its array of server controls that expose sophisticated behaviors, such as data binding and validation, along with a rich programming model that can directly interact with these server controls. XML and XSLT technology has also made website development better by allowing the separation of content and presentation.
A common way of using XML in ASP websites is to format dynamic information, such as query results, into a destination format (HTML or PDF). However, if you wanted to allow the user to interact with the returned information via a form, you had to use a mix of traditional ASP techniques, such as iterating over the Request.Form collection, and outputting HTML form elements. This approach works with .NET, but you lose the powerful features of ASP.NET server controls, such as data binding, state management, input validation, and the rich event model.
If you have used strongly typed datasets in .NET, you have seen the power of combining XML with the .NET platform. A strongly typed dataset consists of a number of classes whose code is generated by an XML document that defines what the code should do. The xsd.exe tool then generates the actual code based upon the requirements as defined in the XML document. XML then becomes a tool for meta-programming (or generative programming), which is the process of using code to generate code. The goal here is the same - to show how to use XML with an XSLT to generate ASP.NET code, specifically server controls. Utilizing intrinsic ASP.NET parsing methods with the XSLT output, you will have another meta-programming tool to make website development faster, easier, and better.
To illustrate this technique, we will create an example application - a custom survey system, where an XML document defines the structure of a web survey. The XSLT defines the layout and behavior of the web page, as well as postback behavior, allowing for a completely dynamic system, which, by using ASP.NET cross browser support, will work on all browsers. This dynamic nature could be used to allow users or content maintainers to define surveys by creating new XML documents, develop branching surveys based on a previous input, and more, all without the need to manually write any new code. All these feature extensions can be accomplished by editing the XSLT that generates the ASP.NET code.
By allowing non-programmers to create an XML document that will generate code, you can reduce the load on ASP.NET developers, but still leverage all of ASP.NET's power. In essence, you can have a system that allows users to specify what they want, and not need to know how to make it happen. This particular example will use a simple results storage system, as well as omitting some processes that would be needed in a robust system, as the purpose is not to present a complete system, but to illustrate a meta-programming technique.
Requirements
The code and techniques described here require ASP.NET, Windows 2000 or XP, along with IIS. The code is written in C#, and assumes knowledge of ASP.NET, XML and XSLT.
Generation of Server Controls From Text
When Microsoft created ASP.NET, they wanted to allow classic ASP developers to continue using familiar development methods. One of these methods was save and run, where a developer would need only to save a page to apply code changes. This method relied on ASP pages being interpreted, which meant that no compilation step was needed before a page was ready to test and use. However, the .NET platform uses Microsoft Intermediate Language (MIL), which is generated in a compilation stage. To support the save and run development process, ASP.NET utilizes the .NET compiler in a dynamic fashion. This allows the ASP.NET system to recompile a page whenever it detects a change to that page's code. You may have noticed this step when you load an ASP.NET page, there is a brief delay the first time page is loaded. During this time, ASP.NET compiles the code contained in the page, if needed, and the .NET runtime converts the IL into platform-specific machine code.
It is ASP.NET's ability to dynamically compile code that can be used for a system that leverages XML and XSLTs. The general idea is to use the XSLT to create valid ASP.NET code for server controls, then, using built-in methods, parse this code into server controls, and insert those controls into the page structure. Because of the nature of the ASP.NET page lifecycle, the server controls created using this method have the same abilities as those defined when you design a page in Visual Studio.NET.
Details of the Process
To use XML and an XSLT to generate and use ASP.NET code, you need to:
- Define a data source (XML document)
- Create an XSLT to transform XML into ASP.NET code
- Instantiate server controls defined by the generated ASP.NET code at runtime
- Insert the instantiated controls into the page's control collection
- Handle postback events from server controls
The XML document to be used as the data source can be any XML document you want. For example, it could be a user generated or supplied document, the result of a SQL Server XML query, an XML schema, or the result of a SOAP method call. The key is the XSLT that generates the ASP.NET code from the XML data. The ASP.NET code returned by the transformation is then instantiated by the Page.ParseControl method, which is in the System.Web.UI namespace. Note that although the method name suggests instantiation of a single control, this method will instantiate multiple controls, and return them as a control collection. The parsed controls can then be added to the page's control collection, either directly, or as the child of another control on the page.
This process should occur in the page's init event handler, so that the server controls are accessible during the rest of the page's lifetime. In addition, if the controls are added in this event handler, the ASP.NET runtime handles all state management and raising of events, such as button clicks and text changes. This allows you to define server side event handlers and reference the dynamically generated server controls in a standard way.
Dynamically added server controls do suffer from one disadvantage. To reference the controls from code written in the code behind file, you need to get a reference to the control. This can be done with the Page.FindControl method, which returns a reference to the control in the current naming container with the given name. This method uses late-binding, which will decrease performance, so you might want to keep a reference to the returned controls when you instantiate them, perhaps using a HashTable, with the control's name as the key, and reference to the control as the value.
HTML can also be output from the XSLT. The HTML will be converted to Literal controls that can be added to the page. Using HTML elements allows you to format server controls and data without the overhead of full ASP.NET formatting server controls, such as tables and panels. Formatting can also be handled by style attributes, but this comes at the cost of losing support for some older or non-standard browsers that don't fully support style attributes.
With any technology, there are a number of details that can cause problems. Dynamically generating server controls from an XML document is no different. These details are illustrated in the example of this technique.
Custom Survey System Example
The following example is a custom survey system, in which an XML document defines the structure of the survey and the XSLT transforms the survey into server controls. Each step detailed above is illustrated with code examples.
Data Source
A basic survey structure is defined below. In a more robust solution, an XML schema would be written to ensure that all surveys follow the correct format. The example structure consists of a survey element, with a name attribute and one child element for each question. Each question element contains a type attribute, a name attribute, and an optional required attribute. If the question is a multiple-choice question, each choice is a child element of the question.
<survey name="Example Survey">
<question type="text" name="Title" required="yes"/>
<question type="text" name="Industry"/>
<question type="radio" name="Education">
<choice>High school</choice>
<choice>Some college</choice>
<choice>College</choice>
</question>
</survey>
As you can see, in this example there are three questions, two text questions and one multiple-choice question. Note that the first question is required, which means that the server controls should prevent submission of the form if that question is left blank, as can be seen in Figure 2. In a more complete application, validation controls with regular expressions could be used, or any other technique available in ASP.NET.
Create XSLT
The XSLT is the key to the process as it generates the ASP.NET code that will create the 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:template match="/">
<table>
<xsl:for-each select="//question">
<tr>
<td valign="top"><xsl:value-of select="@name" />
<xsl:if test="@required = 'yes'">
<asp:RequiredFieldValidator ErrorMessage="Required
Field" runat="server" ControlToValidate="{@name}" />
</xsl:if>
</td>
<td>
<xsl:if test="@type='text'">
<asp:TextBox id="{@name}" runat="server" />
</xsl:if>
<xsl:if test="@type='radio'">
<asp:RadioButtonList id="{@name}" runat="server">
<xsl:for-each select="choice">
<asp:ListItem Value="{@value}">
<xsl:value-of select="@value"/>
</asp:ListItem>
</xsl:for-each>
</asp:RadioButtonList>
</xsl:if>
</td></tr>
</xsl:for-each>
</table>
<asp:button id="submit" runat="server" Text="Submit" />
</xsl:template>
</xsl:stylesheet>
The XSLT iterates through each question, first outputting a label for the question as plain text. The stylesheet also checks if the field is required, and adds a RequiredFieldValidator if needed. The stylesheet then creates a TextBox for the text questions and a RadioButtonList for the radio questions. ListItems are created for each of the choices in the radio button questions. Surrounding the server control declarations are standard HTML table elements, to format the questions. Finally, a submission button is added to the end of the form.
XML Namespaces
You might notice in the XSLT that a prefix is defined for the XSL namespace. This is so that plain HTML can be generated, and not be interpreted as XSLT commands. HTML is not XML, so it cannot have a prefix if it is to work as HTML, so the HTML element must reside in the default namespace. The XSLT can be directed to omit namespace prefixes, but they are needed for the server controls, which require an asp prefix.
Looking at a page's source in the WebForm designer, it appears that the ASP.NET page's source code is XML. While the code is similar to XML, in both format and intent, it is not XML. The main effect of this code format for this article is that a namespace declaration is not allowed in ASP.NET server control declarations. However, the namespace prefix is required, which is why it is defined in the XSLT as xmlns:asp="remove". After the XSLT is applied to the XML, the server controls have a format like <asp:TextBox ... xmlns:asp="remove"/>, which is not legal. But, if the namespace declaration is removed, then the result is valid ASP.NET source code.
Instantiate Controls
Once the XSLT has been applied to the XML and the appropriate namespace declarations have been removed, all that is left is to instantiate the controls and add them to the page. Calling the Page.ParseControl method and capturing the returned control, which is actually a collection of controls, is the way to do this. This control collection is then added to the survey control's control collection and the process is complete. The survey control is a PlaceHolder control, which allows placement of the survey to be done as a single unit on a larger page and allows for management of the visibility of the survey as a whole.
For this system, all these steps are wrapped into one method, CreateSurvey, which loads the XSLT, transforms the XML, and removes the namespace references for the server controls. The method is called from the page's init event handler, as this ensures that the state and all events for the controls are processed correctly. For the full code of the init event handler, please see the code download available at the end of the article.
// called from Page's Init event handler
private void CreateSurvey() {
// Load the data source
XPathDocument surveyDoc = new
XPathDocument(Server.MapPath("ExSurvey.xml"));
// Load the xslt to do the transformations
XslTransform transform = new XslTransform();
transform.Load(Server.MapPath("MakeControls.xslt"));
// Get the transformed result
StringWriter sw = new StringWriter();
transform.Transform(surveyDoc, null, sw);
string result = sw.ToString();
// remove the namespace attribute
result = result.Replace("xmlns:asp=\"remove\"", "");
// parse the control(s) and add it to the page
Control ctrl = Page.ParseControl(result);
survey.Controls.Add(ctrl);
}
Process Results
In a full custom survey system, the results from a submitted survey could be saved to a database, via some sort of data access objects. However, for this example, the results will simply be sent via email. The XML document that defines the question is used here again, but this time by iterating over the questions to get the answers to each one by use of the Page.FindControl method.
private void ProcessSurveyResults () {
// Load the data source
XPathDocument surveyDoc = new XPathDocument(Server.MapPath("ExSurvey.xml"));
// create an iterator for each question
XPathNodeIterator itr =
surveyDoc.CreateNavigator().Select("//question");
// string builder for survey body
System.Text.StringBuilder sb;
sb = new System.Text.StringBuilder();
// submission information
sb.Append("Survey submitted on " + DateTime.Now + Environment.NewLine);
// foreach question
while (itr.MoveNext()) {
// get the control name
string controlName = itr.Current.GetAttribute("name", "");
// append question information
sb.Append(controlName);
sb.Append(" : ");
// get the control
object ctrl = FindControl(controlName);
// append the correct filled out information
if (ctrl is TextBox) {
sb.Append(((TextBox)ctrl).Text);
}
if (ctrl is RadioButtonList) {
// the selected item might be null
if (((RadioButtonList)ctrl).SelectedItem != null) {
sb.Append(((RadioButtonList)ctrl).SelectedItem.Value);
}
}
sb.Append(Environment.NewLine);
}
string body = sb.ToString();
// send the results
// NOTE In a full application, these settings should be stored
// in a configuration file, so that the email addresses and server
// address can be changed without editing the code
System.Web.Mail.SmtpMail.SmtpServer = "your.smtp.server";
System.Web.Mail.SmtpMail.Send("survey@somewhere.com", "your@address.com",
"Survey result", body);
}
Other Details
The only other item needed for the sample application is a label thanking the user for his/her input, which is made visible when the form is submitted (to prevent double responses). You know when the page is submitted by looking at the IsPostBack member variable, which is set to true when the page has been submitted. Be aware that the IsPostBack variable can also true when a server event is raised, so in a full system you would want to check which control caused the postback before processing the survey results. Assuming that the postback is caused by user submitting the survey, the label thanking the user is made visible and the survey control is made invisible. This all occurs in the page's load event handler, along with any other code needed for the rest of the page.
if (IsPostBack) {
ProcessSurveyResults();
survey.Visible = false;
ThankYouLabel.Visible = true;
} else {
survey.Visible = true;
ThankYouLabel.Visible = false;
}
Example Setup
All the code discussed here is included in a zip file, which can be downloaded via the link at the end of this article. It is in the form of a Visual Studio.NET Web Application project, but it does not require Visual Studio.NET. To install the custom survey example, extract the files to a directory, and then share that directory in IIS. If you want to use the email notification for survey results, change the SMTP server and email addresses in the ProcessSurveyResults method in WebForm1.aspx.cs to appropriate values for your network.
Enhancements
The number of possibilities for the XML/XSLT/server control combination is enormous. Web Services return data in an XML format (SOAP), and so this technique can be leveraged as part of a Web Services system. For example, you could create a custom Web Services browser, where the application queries the server, and then allows the execution of methods exposed by the Web Service via a dynamically generated form. This could look similar to the Microsoft Web Service interface, which uses the SOAP information generated when a method is marked with the WebMethod attribute. The Microsoft interface is visible by loading a web service URL in a browser. By using server controls and XSLT, a new interface can be created and be completely customized. Other ideas leverage SQL Server, which can return SQL data, so a data entry interface could be dynamically generated, thus eliminating the need to write administrative webform code, as well as ensuring business rules are enforced via the rich functionality that server controls provide.
Conclusion
The ability to separate data from content leads to cleaner design and better maintainability. This was the promise of XML, and it is still valid. The abilities of ASP.NET server controls are a leap forward in web UI development. When combined with XML and XSLT, ASP.NET server controls become even more powerful as a meta-programming tool. Allowing XML data to drive both presentation format and appearance, as well as behavior, opens up numerous possibilities for dynamic and robust systems.
By Wrox Team
Source: devarticles.com

Comments (4)
This is something a dream come true for me.
When I saw the title of the page on google search, I was not very different from "a deer in headlight'".
Is the source code avaliable for this? I am not able to find the code.
Thats really a praiseworthy implementation, but i wished i could create asp pages without using XSLT.
Can we achieve creation of aspx pages by just using XML, and not XSLT? Any ideas? Can somebody throw light on it?
I love this approach. However, as I try to use controls from the AjaxControlToolkit, I'm getting Parse errors, and I think it might be a namespace problem but I can't resolve the problem. Any thoughts?