Designing the Guestbook: Forms, XML Storage, and XSL Transformation
When you set out to build a guestbook for an ASP.NET site, the first thing you decide is how the data will flow from the user to the server and back again. A clean way to keep the logic separate from the layout is to split the interface into two distinct pages: one for signing in, and another for viewing the list of entries. This separation lets each page focus on a single responsibility and keeps the code easier to read.
The signing page, which we’ll call guestbook.aspx, contains a handful of fields that capture the essentials a visitor usually shares. Most implementations record the name, location, email address, website URL, and a short comment. Adding more fields is straightforward, but these five are the minimum that give a useful record without overloading the form.
Because the goal of this tutorial is to avoid a full database setup, the data is stored in an XML file named guestbook.xml. XML works well for lightweight persistence: it’s human readable, can be edited directly, and fits naturally with XSLT, the transformation engine we’ll use later to render the entries as HTML. The XML file’s structure is simple yet flexible; each entry is wrapped in a <guest> element that contains child elements for every field:
Notice the root element <guestbook> that encloses all guest entries. Each <guest> element is a self-contained record. By keeping the XML hierarchy flat and predictable, the XSLT processor can walk through the data effortlessly.
To translate the raw XML into a friendly HTML table, we write a short XSL stylesheet called guestbook.xsl. XSLT’s for-each loop iterates over every <guest> element, and a simple template renders the values inside table rows. A minimal example looks like this:
This stylesheet produces a simple, well‑formatted table without any server‑side code. The power of XSLT lies in its declarative nature: the template declares how each node should be rendered, and the processor takes care of the rest. By separating presentation from data, you can change the look of the guestbook by editing a single XSL file, while the underlying XML remains untouched.
Putting these pieces together, the architecture of the guestbook looks like this:
guestbook.aspx– the form where visitors submit their information.guestbook.cs– code behind that receives the form data and appends a new<guest>node toguestbook.xmlviewguestbook.aspx– a lightweight page that loads the XML and passes it throughguestbook.xslto generate the display.viewguestbook.cs– code behind that wires the XML transformation and writes the result to the response stream.guestbook.xml– the persistent store of all entries.guestbook.xsl– the stylesheet that shapes the output into an HTML table.With the design laid out, the next step is to bring the components to life through actual ASP.NET code. By following the pattern outlined here, you keep the project modular, easy to debug, and simple enough to extend later if you decide to replace the XML backend with a database or add email notifications.
Implementing the Guestbook: Code Behind and Page Flow
The implementation starts with the markup of
guestbook.aspx. The page declares that it uses a code‑behind file namedGuestbook.csand that it inherits from the classGuestbook. The form itself contains five input controls:txtName,txtLocation,txtEmail,txtWebsite, andtxtComment. Each control is paired with a validator that ensures the field is not left empty before the form posts back. Finally, a submit button wired to theSave_Commentevent triggers the write to XML, and a reset button clears the fields.<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Guestbook.cs" Inherits="Guestbook" %></p> <p><%@ Register Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"</p> <p> Namespace="System.Web.UI" TagPrefix="asp" %></p> <p><asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server"></p> <p> <asp:TextBox ID="txtName" runat="server" Width="200px"></asp:TextBox></p> <p> <asp:RequiredFieldValidator ID="valName" runat="server" ControlToValidate="txtName"</p> <p> ErrorMessage="Name required." Text="*" ForeColor="Red"></asp:RequiredFieldValidator></p> <p> <asp:Button ID="btnSave" runat="server" Text="Submit" OnClick="Save_Comment" /></p> <p> <asp:Button ID="btnReset" runat="server" Text="Reset" CausesValidation="false" /></p> <p></asp:Content></p>The code behind,
Guestbook.cs, is where the magic happens. At the top, the standard namespaces are included:System,System.Web,System.Xml, andSystem.IO. The classGuestbookexposes the five text boxes as public members so the ASP.NET runtime can wire them automatically.The
Save_Commentmethod is the event handler for the submit button. Inside, it calls a private helper,SaveXMLData, passing the values from the text boxes. This helper opens (or creates if it does not exist) theguestbook.xmlfile, loads it into anXmlDocument, and builds a new<guest>node with child elements populated by the user input. Once the node tree is assembled, it is appended to the root<guestbook>element and the entire document is written back to the file.Here is the core of
SaveXMLData:private void SaveXMLData(string name, string location, string email, string website, string comment)</p> <p>{</p> <p> string path = Server.MapPath("~/guestbook.xml");</p> <p> XmlDocument xmlDoc = new XmlDocument();</p> <p> if (File.Exists(path))</p> <p> xmlDoc.Load(path);</p> <p> else</p> <p> {</p> <p> XmlDeclaration dec = xmlDoc.CreateXmlDeclaration("1.0", "UTF-8", null);</p> <p> xmlDoc.AppendChild(dec);</p> <p> XmlNode root = xmlDoc.CreateElement("guestbook");</p> <p> xmlDoc.AppendChild(root);</p> <p> }</p> <p> XmlNode rootNode = xmlDoc.DocumentElement;</p> <p> XmlNode guestNode = xmlDoc.CreateElement("guest");</p> <p> XmlNode nameNode = xmlDoc.CreateElement("name");</p> <p> nameNode.InnerText = name;</p> <p> guestNode.AppendChild(nameNode);</p> <p> XmlNode locNode = xmlDoc.CreateElement("location");</p> <p> locNode.InnerText = location;</p> <p> guestNode.AppendChild(locNode);</p> <p> XmlNode emailNode = xmlDoc.CreateElement("email");</p> <p> emailNode.InnerText = email;</p> <p> guestNode.AppendChild(emailNode);</p> <p> XmlNode webNode = xmlDoc.CreateElement("website");</p> <p> webNode.InnerText = website;</p> <p> guestNode.AppendChild(webNode);</p> <p> XmlNode commNode = xmlDoc.CreateElement("comment");</p> <p> commNode.InnerText = comment;</p> <p> guestNode.AppendChild(commNode);</p> <p> rootNode.AppendChild(guestNode);</p> <p> xmlDoc.Save(path);</p> <p>}</p>After the data is saved, the page redirects to
viewguestbook.aspx, ensuring the user sees their entry reflected immediately.The viewer page is intentionally minimal. The markup contains only a reference to the code behind,
ViewGuestbook.cs. In the code behind’sPage_Loadmethod, the XML file is reloaded and passed to anXslCompiledTransforminstance along with the XSL stylesheet. The transform produces a stream of HTML that is then written directly to the response, avoiding any server‑side rendering overhead.Below is the key part of
ViewGuestbook.cs:using System;</p> <p>using System.Xml;</p> <p>using System.Xml.Xsl;</p> <p>using System.IO;</p> <p>public partial class ViewGuestbook : System.Web.UI.Page</p> <p>{</p> <p> protected void Page_Load(object sender, EventArgs e)</p> <p> {</p> <p> string xmlPath = Server.MapPath("~/guestbook.xml");</p> <p> string xslPath = Server.MapPath("~/guestbook.xsl");</p> <p> XslCompiledTransform xslt = new XslCompiledTransform();</p> <p> xslt.Load(xslPath);</p> <p> using (MemoryStream ms = new MemoryStream())</p> <p> {</p> <p> xslt.Transform(xmlPath, null, ms);</p> <p> ms.Position = 0;</p> <p> using (StreamReader sr = new StreamReader(ms))</p> <p> {</p> <p> Response.Write(sr.ReadToEnd());</p> <p> }</p> <p> }</p> <p> }</p> <p>}</p>When a user navigates to
viewguestbook.aspx, the page loads the latest XML, transforms it, and outputs a clean HTML table of all guest entries. If the XML file is missing or empty, the XSLT engine simply produces an empty table, so no error handling is required beyond ensuring the file is available.Deploying this guestbook is straightforward. Drop the six files -
guestbook.aspx,Guestbook.cs,viewguestbook.aspx,ViewGuestbook.cs,guestbook.xml, andguestbook.xsl- into the root of your ASP.NET application. Ensure the XML file has write permissions for the application pool identity so that new entries can be appended. Once the files are in place, visiting the signing page will let visitors leave their comments, and the viewing page will show the growing list.Because the data lives in plain XML, the guestbook can be backed up by simply copying the
guestbook.xmlfile. If you later decide to migrate to a relational database, the transformation logic stays the same; only the data retrieval code changes.Download the full example, including project files and documentation, here.
Author: Sonu Kapoor – founded Codefinger in 2000, studied E‑Commerce in India, lives in Germany, works as a network consultant and software developer, and contributes to major sites like
Tags





No comments yet. Be the first to comment!