Sometimes you need the basic features of a database but don't want the
hassle, and possibly cost, of creating one for a small application. With
the .NET DataSet
object and a simple XML document we can emulate the basic
features of a database. In this example, we use an XML document which
stores our product information. We want to look up a product by SKU and
return the price and description to a Web page.
We have three products in our list. The following is a basic XML document,
productlist.xml
, containing our data:
<?xml version="1.0" encoding="utf-8" ?>
<ProductList>
<Products>
<SKU>1</SKU>
<Price>100.00</Price>
<Description>Widget #1</Description>
</Products>
<Products>
<SKU>2</SKU>
<Price>10.00</Price>
<Description>Widget #2</Description>
</Products>
<Products>
<SKU>3</SKU>
<Price>30.00</Price>
<Description>Widget #3</Description>
</Products>
</ProductList>
If you think of this document in terms of a database, the data within the
ProductList
tags are our database. The data within the Products
tags are a
table in the database. SKU
, Price
, and Descriptions
are columns in the Products
table. Just like a database, we want to return a row of values,
given a column value.
First, we need to read our XML document into something that .NET can use.
This is very easy to do with the DataSet
object's ReadXml
method. By using
a DataSet
, we can treat our data like a database. Also, compared to using
the .NET XML objects, the DataSet
results in less code and complexity.
All we need to do is create a new DataSet and tell it to read our XML
document into it:
DataSet dsProducts = new DataSet();
dsProducts.ReadXml(Server.MapPath("productlist.xml"));
The ReadXml
method is passed the file name of the XML file to read. This
example assumes that the file is named productlist.xml
and is located in the
same directory as the page using it.
Now that we have our data in a DataSet
, we need to be able to query it for
an SKU
and return the Price
and Description
for the corresponding product.
To do this, we will use a DataView
object:
DataView dvProducts = new DataView(dsProducts.Tables["Products"]);
dvProducts.Sort = "SKU";
The DataView
is created by passing the constructor a DataTable
, "Products", in our DataSet
. After we create the DataView
, we need to sort it. Since we
are using the SKU
as the lookup value, we need to sort on it. This is
similar to an index or primary key in a database. If we don't sort the
DataView, we will get a runtime error when we try to use it's Find
method.
With our DataView
sorted, use the Find
method to return only the row(s)
which match the SKU
we give it. In this example, we want to return the
Price
and Description
for a product with a SKU
equal to 1:
int rowIndex = dvProducts.Find("1");
string Price, Description;
if (rowIndex == -1)
{
// The SKU was not found in our data
Response.Write("SKU not found");
}
else
{
Price = dvProducts[rowIndex]["Price"].ToString();
Response.Write("Price: " + Price + "<br>";
// Price: 100.00
Description = dvProducts[rowIndex]["Description"].ToString();
Response.Write("Description: " + Description);
// Description: Widget #1
}
The Find
method of a DataView
returns and int which is the index of the row
in the DataView
containing the sort key value passed to it. If there is no
match, it returns -1.
That's all there is to it. For simple uses, this method of storing and
retrieving information may be much easier than using a database, however,
there are a few things you should keep in mind. First, our simple XML
document stores all data as text strings. This isn't too much of a problem
since we can use the .NET data types to parse our string data to other types
like integer and datetime, but remember when you pass the key value to the
Find
method that it needs to be a string. Second, if we only want one "row"
of data returned for a lookup key, we need to ensure that we don't duplicate
the key in our XML document--in a database we could easily enforce this by
setting the column to be an identity column.
If you are using this method in a busy ASP.NET application where you have a
relatively small amount of data and your data doesn't change too often, you
may want to store the DataSet
object in cache so the XML document doesn't
need to be read and parsed for each request. Use a CacheDependency
on the
XML file to ensure that the cache is expired when the document is updated.
Download the following for complete code in a console application:
using System;
using System.Data;
namespace productsxml
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class main
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
//
// TODO: Add code to start application here
//
DataSet dsProducts = new DataSet();
dsProducts.ReadXml("productlist.xml");
DataView dvProducts = new
DataView(dsProducts.Tables["Products"]);
dvProducts.Sort = "SKU";
int rowIndex = dvProducts.Find("1");
string Price, Description;
if (rowIndex == -1)
{
// The SKU was not found in our data
Console.WriteLine("Product Not found");
}
else
{
Price = dvProducts[rowIndex]["Price"].ToString();
Console.WriteLine("Price: " + Price);
// Price: 100.00
Description = dvProducts[rowIndex]
["Description"].ToString();
Console.WriteLine("Description: " + Description);
// Description: Widget #1
}
}
}
}