A DataSet in Asp.Net , represents an in-memory cache of data retrieved from a variety of data source, such as, SQL Server. We can also use the DataSet Class to read data from an XML file. Combining DataSet with the DataRow Class, we can easily update an XML file.
In this example, I am also using LINQ methods to retrieve each element in an XML file and display it on my web page.
What is this Example?
The XML file (see below) has many node’s. However, I wish to update the Price for each selected book. I’ll allow my users to change the price on my web page. The user will select a book from the <select> dropdown element and click the Show Details button. Once clicked, the click event at the code behind section will fetch misc details about the book from the XML file (matching the selected book), and show it.
The price will display in a textbox control, which will allow the user necessary changes and finally click another button to save the new price in file.
First, you will need some XML data. Here it is.
Create a file with the name library.xml and add the below data to it.
<?xml version="1.0" standalone="yes"?> <Library> <List> <Code>001</Code> <BookName>Computer Architecture</BookName> <Category>Computers</Category> <Price>125.60</Price> </List> <List> <Code>002</Code> <BookName>Advanced Composite Materials</BookName> <Category>Science</Category> <Price>172.56</Price> </List> <List> <Code>003</Code> <BookName>Asp.Net 4 Blue Book</BookName> <Category>Programming</Category> <Price>56.00</Price> </List> <List> <Code>004</Code> <BookName>Stategies Unplugged</BookName> <Category>Science</Category> <Price>99.99</Price> </List> <List> <Code>005</Code> <BookName>Teaching Science</BookName> <Category>Science</Category> <Price>164.10</Price> </List> <List> <Code>006</Code> <BookName>Challenging Times</BookName> <Category>Business</Category> <Price>150.70</Price> </List> <List> <Code>007</Code> <BookName>Circuit Bending</BookName> <Category>Science</Category> <Price>112.00</Price> </List> <List> <Code>008</Code> <BookName>Popular Science</BookName> <Category>Science</Category> <Price>210.40</Price> </List> <List> <Code>009</Code> <BookName>ADOBE Premiere</BookName> <Category>Computers</Category> <Price>62.20</Price> </List> </Library>
In the markup section, I have added an HTML5 <select> element with no values. I’ll add values to it dynamically, that is, through code behind procedure when the page loads. Along with it, I have 2 buttons to show and edit values to the XML file.
<head> <title>Linq to XML Example - Update or Edit XML Data using LINQ</title> <style> div, select, button, span { font:13px Verdana; } div { margin:5px 0; } span { font-weight:bold; } </style> </head> <body> <form runat="server"> <div style="width:350px;border:solid 1px #CCC;padding:10px;"> <p> <%--ADD HTML5 SELECT ELEMENT.--%> <select id="selBooks" runat="server"> <option value="">-- Select your book --</option> </select> <%--BUTTON TO SHOW THE XML DATA.--%> <button id="btShow" onserverclick="show_details" runat="server"> Show Details </button> </p> <div id="container" visible="false" runat="server"> <div> <span>Code: </span> <label id="lblCode" runat="server"></label> </div> <div><label id="lblXML" runat="server"></label></div> <div> <span>Price ($):</span> <input type="text" id="tbPrice" style="width:100px;" runat="server" /> <%--BUTTON TO SAVE (EDIT) XML DATA.--%> <asp:Button style="color:#000;width:100px;margin:0 0 20px 0;" id="btSave" OnClick="save" Text="Edit" runat="server" /> </div> </div> <p><label id="msg" runat="server"></label></p> </div> </form> </body>
using System; using System.Collections.Generic; using System.Linq; // FOR Descendants. using System.Xml; // FOR XmlTextReader. using System.Xml.Linq; // FOR XDocument. using System.Data; // FOR DataSet. public partial class SiteMaster : System.Web.UI.MasterPage { protected void Page_Load(object sender, System.EventArgs e) { if (!IsPostBack) { // LOAD AND READ XML DATA. XmlTextReader xlRead = new XmlTextReader(Server.MapPath("library.xml")); while (xlRead.Read()) { xlRead.MoveToElement(); // POPULATE SELECT ELEMENT. switch (xlRead.NodeType) { case XmlNodeType.Element: if (xlRead.Name.Trim() == "BookName") { selBooks.Items.Add(xlRead.ReadString()); } break; } } xlRead.Close(); } } protected void show_details(object sender, EventArgs e) { msg.InnerHtml = ""; ViewDetails(selBooks.Value.Trim()); } private void ViewDetails(string sBookName) { // LOAD XML DOCUMENT. var xml_Doc = XDocument.Load(Server.MapPath("library.xml")); IEnumerable<XElement> search_books = null; search_books = from xFi in xml_Doc.Descendants("List") where xFi.Element("BookName").Value.Contains(sBookName) select xFi; // NOW DISPLAY THE RESULT. if ((search_books != null)) { lblXML.InnerHtml = ""; foreach (XElement result in search_books) { lblCode.InnerText = result.Element("Code").Value; lblXML.InnerHtml = lblXML.InnerHtml + "<b> Release Date: </b>" + result.Element("ReleaseDate").Value + "<br />" + "<b> Book Name: </b>" + result.Element("BookName").Value + "<br />" + "<b> Category: </b> " + result.Element("Category").Value; tbPrice.Value = result.Element("Price").Value; } container.Visible = true; } else { lblXML.InnerHtml = "Found Nothing"; } } // SAVE (EDIT) DATA TO XML USING THE DataSet CLASS. protected void save(object sender, EventArgs e) { if (Double.Parse(tbPrice.Value) != 0) { using (DataSet ds = new DataSet()) { ds.Dispose(); ds.ReadXml(Server.MapPath("library.xml")); DataRow dr = ds.Tables["list"].NewRow(); // I AM USING THE XML NODE "Code" TO REPRESENT THE ROW, FOR WHICH I'LL UPDATE THE PRICE. ds.Tables["list"].Rows[int.Parse(lblCode.InnerText) - 1]["price"] = tbPrice.Value; ds.AcceptChanges(); // WRITE THE UPDATED DATA INTO THE FILE. ds.WriteXml(Server.MapPath("library.xml")); } ViewDetails(selBooks.Value); msg.InnerHtml = "Data updated sucessfully for the book <b>" + selBooks.Value + "</b>"; } } }
Don’t get overwhelmed by the size of the code here. Simply focus on the save procedure at the end of the code. The remaining code using LINQ is to extract and display data on our web page.
Using the DataSet’s ReadXML() method, we’re actually pushing the data to the DataSet object. It creates a temporary table. Next, using the DataRow class, I am creating a row each for the selected XML element and at the same time assigning a new value to the price node.
ds.Tables["list"].Rows[int.Parse(lblCode.InnerText) - 1]["price"] = tbPrice.Value;
Later, I am asking it to accept or commit the changes made.
ds.AcceptChanges();
Finally, using DataSet’s writeXml(), I am saving the changes in the file.
Option Explicit On Imports System.Xml Imports System.Data ' FOR DataSet. Partial Class Site Inherits System.Web.UI.MasterPage Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load If Not IsPostBack Then ' LOAD AND READ XML DATA. Dim xlRead As New XmlTextReader(Server.MapPath("library.xml")) While xlRead.Read() xlRead.MoveToElement() ' POPULATE SELECT ELEMENT. Select Case xlRead.NodeType Case XmlNodeType.Element If Trim(xlRead.Name) = "BookName" Then selBooks.Items.Add(xlRead.ReadString) End If End Select End While xlRead.Close() End If End Sub Protected Sub show_details(ByVal sender As Object, ByVal e As EventArgs) msg.InnerHtml = "" ViewDetails(Trim(selBooks.Value)) End Sub Private Sub ViewDetails(ByVal sBookName As String) ' LOAD XML DOCUMENT. Dim xml_Doc = XDocument.Load(Server.MapPath("library.xml")) Dim search_books As IEnumerable(Of XElement) search_books = (From xFi In xml_Doc.Descendants("List") _ Where xFi.Element("BookName").Value.Contains(sBookName) ) ' NOW DISPLAY THE RESULT. If Not search_books Is Nothing Then lblXML.InnerHtml = "" For Each result As XElement In search_books lblCode.InnerText = result.Element("Code").Value lblXML.InnerHtml = lblXML.InnerHtml & _ "<b> Release Date: </b>" & result.Element("ReleaseDate").Value & "<br />" & _ "<b> Book Name: </b>" & result.Element("BookName").Value & "<br />" & _ "<b> Category: </b> " & result.Element("Category").Value tbPrice.Value = result.Element("Price").Value Next container.Visible = True Else lblXML.InnerHtml = "Found Nothing" End If End Sub Protected Sub save(ByVal sender As Object, ByVal e As EventArgs) If Val(tbPrice.Value) <> 0 Then ' SAVE (EDIT) DATA TO XML USING THE DataSet CLASS. Using ds As New DataSet() ds.Dispose() ds.ReadXml(Server.MapPath("library.xml")) Dim dr As DataRow = ds.Tables("list").NewRow() ' I AM USING THE XML NODE "Code" TO REPRESENT THE ROW, FOR WHICH I'LL UPDATE THE PRICE. ds.Tables("list").Rows(Val(lblCode.InnerText) - 1)("price") = tbPrice.Value ds.AcceptChanges() ds.WriteXml(Server.MapPath("library.xml")) ' WRITE THE UPDATED DATA INTO THE FILE. End Using ViewDetails(selBooks.Value) msg.InnerHtml = "Data updated sucessfully for the book <b>" & selBooks.Value & "</b>" End If End Sub End Class