Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Creating Guestbook using XML and ADO.NET

0.00/5 (No votes)
6 Aug 2002 1  
Demonstrates capabilities of ADO.NET to deal with XML, by creating a guestbook.

Introduction

Different types of guestbooks have been created by web developers around the world. Assuming people don't get enough with guestbooks, I would like to add another one. My objective is not to produce a complete, ready to deploy guestbook, but merely to demonstrate the capabilities of .NET Framework to deal with XML files and XML Schema through ADO.NET objects. This guestbook is kept simple and straightforward, so you could modify it easily to suit your needs or cater more demanding tasks.

The XML guestbook, so I called it, is very suitable for websites with no access to the database, or those webmasters who do not want to go too far to provide a guestbook in their website. Additionally, you could easily edit the XML file to remove unwanted entries using as simple an application as a Notepad.

I will use ADO.NET objects (DataSet, DataTable, DataRow, DataColumn, and DataView) to access and manipulate XML data for the XML guestbook. There are some alternative approaches to do so, like using .NET XML classes. However, at this time, I personally recommend using ADO.NET since it could represent XML data as a relational information as if you are working on a real relational database.

Defining Table Structure

The XML guestbook will have a table with structure like this:

Column Name    Data Type    Properties
Id             Int32        Primary Key, Auto Increment
Time           DateTime
Author         String
Subject        String
Comments       String

This is the data structure we are going to work on throughout the script. Using ADO.NET, we could use DataTable and DataColumn objects to define the table structure programmatically. The following statements create an instance of DataSet and identify it as myDataSet. Then we create an instance of DataTable as a new table from myDataSet, name it as guestbook, and identify it as myDataTable.

Dim myDataSet As DataSet = New DataSet
Dim myDataTable As DataTable = DataSet.Tables.Add("guestbook")

Once a new table is created, we could start defining columns and their properties as shown in the following codes. The first line creates an instance of DataColumn as a new column of myTable, names it as id with Int32 (4-byte integer) data type, and identifies it as myDataColumn. Then, in the With block, we set the auto increment on, starting from 1 (incrementseed), and adding 1 (incrementstep) every time a new entry comes in. The last three lines are a bit more complex. We want to set the primary key of myTable using its PrimaryKey property. But since PrimaryKey property only accepts an array of DataColumn, first we have to define an one-element array of DataColumn type, assign myDataColumn as its member, and finally set the PrimaryKey to the array. The idea behind this is to allow you to assign more than one column as primary key. So you could have a composite primary key made of more than one column.

Dim myDataColumn as DataColumn = myTable.Columns.Add("id", 
    Type.GetType("System.Int32"))

With myDataColumn
    .AutoIncrement = true
    .AutoIncrementSeed = 1
    .AutoIncrementStep = 1
End With

Dim arrPrimaryKey(1) As DataColumn
arrPrimaryKey(0) = myDataColumn
myTable.PrimaryKey = arrPrimaryKey

Defining the remaining columns is easier because we don't want to put any constraints. We could write shortcuts as follows:

myTable.Columns.Add("datetime", Type.GetType("System.DateTime"))
myTable.Columns.Add("author", Type.GetType("System.String"))
myTable.Columns.Add("subject", Type.GetType("System.String"))
myTable.Columns.Add("comments", Type.GetType("System.String"))

We could add new rows in the table programmatically using a simple statement like this:

myDataTable.Rows.Add(new Object() { 1, DateTime.Now, 
    "Author A", 
    "Subject A", 
    "Comments A"})

This single line of code creates an array of Object, sets the values, and adds to the DataRow collection of myDataTable. The sequence of the values must match with the sequence of the columns we defined earlier.

There is a more verbose approach and I personally prefer this for clarity.

Dim myDataRow As DataRow = myDataTable.Rows.NewRow()
myDataRow("id") = 1
myDataRow("time") = DateTime.Now
myDataRow("author") = "Author A"
myDataRow("subject") = "Subject A"
myDataRow("comments") = "Comments A"
myDataTable.Rows.Add(myDataRow)

Storing Table Structure as XML Schema

The table structure should be stored so that we don�t need to define the table every time we use it. The table structure could be stored as an XML schema. Simply, an XML schema is a set of rules to govern how the elements and attributes in an XML file are written. An XML schema could be written in a separate file with an xsd extension, or within an XML file it refers to. The latter is called as inline XML schema.

Luckily, DataSet object already has capabilities to write and read schema, so we don�t need to devise our own way. The WriteXml method writes the entire content of the DataSet into an XML file, and optionally writes the table structure as an inline XML schema. Conversely, we read back data from an XML file to DataSet by using ReadXml method. Again, we have the option to read the schema or not, although it is recommended to read the schema, if it exists, to ensure data validity and consistency during manipulation. In the XML guestbook case, this mechanism ensures that new data we add to the DataTable always adheres with the table structure defined earlier (i.e. the id column always increments automatically and the time field always contains valid DateTime data type).

Statements to call WriteXml and ReadXml methods are as follows:

DataSet.WriteXml(Server.MapPath("guestbook.xml", XMLWriteMode.WriteSchema))

DataSet.ReadXml(Server.MapPath("guestbook.xml", XMLReadMode.ReadSchema))

The second parameter of each method is optional. If you don't determine one, the default value is Auto, which means the .NET Framework will scan the XML file first. It will use an XML schema if it finds one, otherwise automatically creates a new one with a process known as "schema inference". There are some other XmlWriteMode and XmlReadMode options I don't mention here. For a complete description, please consult MSDN.

Server.MapPath is used to convert a virtual address (as recognized by IIS) to a physical address. In this case, we assume guestbook.xml resides in the same folder as the aspx file, and the folder has a write permission.

A table structure we defined earlier, while stored as an XML schema, will look like this:

<?xml version="1.0" standalone="yes"?>
<NewDataSet>
  <xs:schema id="NewDataSet" xmlns=""
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xs:element name="NewDataSet" msdata:IsDataSet="true">
      <xs:complexType>
        <xs:choice maxOccurs="unbounded">
          <xs:element name="guestbook">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="id" msdata:AutoIncrement="true"
                msdata:AutoIncrementSeed="1" type="xs:int" />
                <xs:element name="datetime" type="xs:dateTime"
                minOccurs="0" />
                <xs:element name="author" type="xs:string"
                minOccurs="0" />
                <xs:element name="subject" type="xs:string"
                minOccurs="0" />
                <xs:element name="comments" type="xs:string"
                minOccurs="0" />
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:choice>
      </xs:complexType>
      <xs:unique name="Constraint1" msdata:PrimaryKey="true">
        <xs:selector xpath=".//guestbook" />
        <xs:field xpath="id" />
      </xs:unique>
    </xs:element>
  </xs:schema>
</NewDataSet>

Don�t worry about the complexity of the XML schema produced. Since ADO.NET handles the schema in the background, it is in rare cases you need to get into it.

Displaying Data

Now comes the fun part. You have a wide range of choices to display the guestbook data. You can use Repeater, DataList, DataGrid, or create your own control to suit your design requirements. In this example, I use Repeater control since it allows greater flexibility than its more popular sister: the DataGrid.

To display the content of the DataSet in the Repeater control, you have to bind DataSet object to Repeater. The following chunk of code just does that:

Dim myDataView As DataView = myDataSet.Tables(0).DefaultView

myRepeater.DataSource = myDataView
myRepeater.DataBind()

First, you create a DataView object from the current table. Since the table is the first and the only table in the DataSet, it always has index 0 in the table collection. So you could refer it either as Tables(0) or Tables("guestbook"). Then we set the DataSource property of the Repeater to the DataView object, and call DataBind method to effectively bind data to the Repeater.

The content of the guestbook will appear in ascending order, which makes the newer messages display later. If you want to reverse the order, insert the following statement before calling the DataBind method.

myDataView.Sort = "id DESC"

This will sort the DataView based on column id in descending order. Notice the similarity of the value to SQL statement.

Following the Repeater control, I put a form with three textboxes: Author, Subject, and Comments, to allow visitors write their thoughts on the guestbook. Again, it is very straightforward. You could redesign the form to suit your design or put validation so that visitors won't leave blank entries.

Conclusions

Thanks to the strong relationship between ADO.NET objects and XML, now we could easily manipulate XML data as relational information, as if we work on a relational database. We could store our relational tables into an XML file and retrieve them back while still retaining their data structure. The programming technique mentioned here would suit small tasks that require a straightforward and fast data storage by avoiding much overhead in a typical SQL database.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here