Linq to XML Tutorial

Download source

This is an introduction to Linq to XML showing how to read, insert, update and delete from an XML file.

First of all lets look at the XML file I will be using:

<?xml version="1.0" encoding="utf-8"?>
<Customers>
 <Customer ID="1">
  <Forename>Joe</Forename>
  <Surname>Stevens</Surname>
  <DOB>31/01/1983</DOB>
  <Location>Sydney</Location>
 </Customer>
 <Customer ID="2">
  <Forename>Tom</Forename>
  <Surname>Male</Surname>
  <DOB>02/02/1977</DOB>
  <Location>Brisbane</Location>
 </Customer>
 <Customer ID="3">
  <Forename>Emily </Forename>
  <Surname>Stevens</Surname>
  <DOB>14/01/1988</DOB>
  <Location>Sydney</Location>
 </Customer>
 <Customer ID="4">
  <Forename>Lee</Forename>
  <Surname>Phipps</Surname>
  <DOB>05/12/1982</DOB>
  <Location>Melbourne</Location>
 </Customer>
 <Customer ID="5">
  <Forename>Saul</Forename>
  <Surname>Stevens</Surname>
  <DOB>02/08/1984</DOB>
  <Location>Perth</Location>
 </Customer>
</Customers>

As you can see it’s a very simple list of customers.  In my project I have also created a Customer class to represent each customer:

public class Customer
{
    public int ID { get; set; }
    public string Forename { get; set; }
    public string Surname { get; set; }
    public string DOB { get; set; }
    public string Location { get; set; }
}

Firsly I want to be able to select a single customer based on their ID.  The following method shows how to load the XML file and query it to find the customer we want, and return the data as a single Customer object:


public static Customer GetCustomer(int customerID)
{
    XDocument data = XDocument.Load(HttpContext.Current.Server.MapPath("~/Data/Customers.xml"));

    return (from c in data.Descendants("Customer")
            where c.Attribute("ID").Value.Equals(customerID.ToString())
            select new Customer()
            {
                ID = Convert.ToInt32(c.Attribute("ID").Value),
                Forename = c.Element("Forename").Value,
                Surname = c.Element("Surname").Value,
                DOB = c.Element("DOB").Value,
                Location = c.Element("Location").Value

            }).FirstOrDefault();
}

Firstly the XML document is loaded using the XDocument class.  I then use Linq to look at all the Customer elements and find the one where the ID attribute matches the value passed to the method.  The Customer object is then populated with each element within the Customer element.

I’ve created a simple web form that uses an ObjectDataSource with this method to display a customer based on the ID in the query string:


<asp:DetailsView
    ID="dvCustomer"
    DataSourceID="odsCustomer"
    runat="server">
</asp:DetailsView>

<asp:ObjectDataSource
    ID="odsCustomer"
    TypeName="LinqToXml.Data.DAL"
    SelectMethod="GetCustomer"
    runat="server">
    <SelectParameters>
        <asp:QueryStringParameter Name="customerID" QueryStringField="id" DefaultValue="1" />
    </SelectParameters>
</asp:ObjectDataSource>

The page creates the following table:

linqtoxml_single

To get a list of all customers is very similar to getting a single customer, although the method will return a generic list of Customer objects:


public static List<Customer> GetCustomers()
{
    XDocument data = XDocument.Load(HttpContext.Current.Server.MapPath("~/Data/Customers.xml"));

    return (from c in data.Descendants("Customer")
            orderby c.Attribute("Surname")
            select new Customer()
            {
                ID = Convert.ToInt32(c.Attribute("ID").Value),
                Forename = c.Element("Forename").Value,
                Surname = c.Element("Surname").Value,
                DOB = c.Element("DOB").Value,
                Location = c.Element("Location").Value

            }).ToList();
}

Here I am also using the orderby operator to order the results by the value of the Surname element.

I have a single method called Save which is used for both inserting and updating.  It accepts a Customer object and performs an insert or update depending on the ID value of that object:


public static void Save(Customer customer)
{
    XDocument data = XDocument.Load(HttpContext.Current.Server.MapPath("~/Data/Customers.xml"));

    if (customer.ID > 0)
    {
        XElement customerElement = data.Descendants("Customer").Where(c => c.Attribute("ID").Value.Equals(customer.ID.ToString())).FirstOrDefault();
        if (customerElement != null)
        {
            customerElement.SetElementValue("Forename", customer.Forename);
            customerElement.SetElementValue("Surname", customer.Surname);
            customerElement.SetElementValue("DOB", customer.DOB);
            customerElement.SetElementValue("Location", customer.Location);

            data.Save(HttpContext.Current.Server.MapPath("~/Data/Customers.xml"));
        }
    }
    else
    {
        XElement newCustomer = new XElement (   "Customer",
                                                new XElement("Forename", customer.Forename),
                                                new XElement("Surname", customer.Surname),
                                                new XElement("DOB", customer.DOB),
                                                new XElement("Location", customer.Location)
                                            );

        newCustomer.SetAttributeValue("ID", GetNextAvailableID());

        data.Element("Customers").Add(newCustomer);
        data.Save(HttpContext.Current.Server.MapPath("~/Data/Customers.xml"));
    }
}

In this method I load the XML document as before and then check the value of customer.ID to see whether to insert or update.

If the value is greater than zero then it is an update.  Firstly I get the element matching the ID using the Where extension method and a lambda expression using the given ID. If the element is found (not null), I use the SetElementValue method to update the values of the child elements with their new values.  After this is done I call save on the XDocument and pass the URL on the original XML file to update it.

If customer.ID is zero then I know this is a new record and I need to perform an insert.  This is done by creating a new XElement with the name Customer, then by creating a list of XElements for the children.  I then set the ID attribute on the Customer element by calling a method called GetNextAvailableID which I’ll explain in a moment.  Now my element is ready to be inserted so using my XDocument I use the Element method to get the Customers element and the Add method to add my new element to it.  As with the update I then need to call the save method on the XDocument.

The GetNextAvailableID method simply finds the highest ID used in the XML document and adds one to it:


private static int GetNextAvailableID()
{
    XDocument data = XDocument.Load(HttpContext.Current.Server.MapPath("~/Data/Customers.xml"));

    return Convert.ToInt32(
            (from c in data.Descendants("Customer")
             orderby Convert.ToInt32(c.Attribute("ID").Value) descending
             select c.Attribute("ID").Value).FirstOrDefault()
            ) + 1;
}

As you can see I’m using Linq to query the XML sorting the result by ID in decending order then selecting the first item; this will be the one with the highest ID. I then add one to that ID and return the value.

The final part of the tutorial is deleting from the XML file:


public static void Delete(Customer customer)
{
    XDocument data = XDocument.Load(HttpContext.Current.Server.MapPath("~/Data/Customers.xml"));

    XElement customerElement = data.Descendants("Customer").Where(c => c.Attribute("ID").Value.Equals(customer.ID.ToString())).FirstOrDefault();
    if (customerElement != null)
    {
        customerElement.Remove();
        data.Save(HttpContext.Current.Server.MapPath("~/Data/Customers.xml"));
    }
}

As with the update code I’m selecting the element based on the customer ID.  Once I have that element all I need to do is call the Remove method on it, then save the XDocument.

I have put all this code to use with a GridView and ObjectDataSource in the following form:

<div>
    <table>
        <tbody>
            <tr>
                <th>
                    Forename
                </th>
                <td>
                    <asp:TextBox ID="txtForename" runat="server" />
                </td>
            </tr>
            <tr>
                <th>
                    Surname
                </th>
                <td>
                    <asp:TextBox ID="txtSurname" runat="server" />
                </td>
            </tr>
            <tr>
                <th>
                    DOB
                </th>
                <td>
                    <asp:TextBox ID="txtDOB" runat="server" />
                </td>
            </tr>
            <tr>
                <th>
                    Location
                </th>
                <td>
                    <asp:TextBox ID="txtLocation" runat="server" />
                </td>
            </tr>
        </tbody>
        <tfoot>
            <tr>
                <td colspan="2">
                    <asp:Button ID="btnAddCustomer" Text="Add Customer" OnClick="btnAddCustomer_Click" runat="server" />
                </td>
            </tr>
        </tfoot>
    </table>
</div>
<div>
    <asp:GridView
        ID="gvCustomers"
        DataSourceID="odsCustomers"
        AutoGenerateColumns="false"
        AutoGenerateEditButton="true"
        AutoGenerateDeleteButton="true"
        DataKeyNames="ID"
        runat="server">
        <Columns>
            <asp:BoundField HeaderText="Forename" DataField="Forename" />
            <asp:BoundField HeaderText="Surname" DataField="Surname" />
            <asp:BoundField HeaderText="DOB" DataField="DOB" />
            <asp:BoundField HeaderText="Location" DataField="Location" />
        </Columns>
    </asp:GridView>

    <asp:ObjectDataSource
        ID="odsCustomers"
        TypeName="LinqToXml.Data.DAL"
        SelectMethod="GetCustomers"
        DataObjectTypeName="LinqToXml.Customer"
        UpdateMethod="Save"
        DeleteMethod="Delete"
        runat="server">
    </asp:ObjectDataSource>
</div>

The only code required on the web form is the code to add a new customer, as the selecting, updating and deleting is handled by the ObjectDataSource by calling the methods discussed above:


protected void btnAddCustomer_Click(object sender, EventArgs e)
{
    Customer customer = new Customer()
    {
        Forename = txtForename.Text.Trim(),
        Surname = txtSurname.Text.Trim(),
        DOB = txtDOB.Text.Trim(),
        Location = txtLocation.Text.Trim()
    };

    Data.DAL.Save(customer);

    ClearForm();
    gvCustomers.DataBind();
    txtForename.Focus();
}

private void ClearForm()
{
    txtForename.Text = string.Empty;
    txtSurname.Text = string.Empty;
    txtDOB.Text = string.Empty;
    txtLocation.Text = string.Empty;
}

My resulting form looks like this:

linqtoxml_multi

Download source

Posted on by Joe in ASP.NET, C#, Linq, XML

46 Responses to Linq to XML Tutorial

  1. Hugo

    Great article, just what I needed to get me started on Linq To XML. Thanks

  2. Joe

    Hi Hugo

    Glad you found it useful.

    Joe

  3. Guenther

    PERFECT !!! THANKS !!

  4. Rajiv

    Its nice article to start LINQ to XML.
    I found it is helpful to understand the Basic Xml operation using LINQ.

  5. Joe

    Hi Rajiv

    Glad it was helpful

  6. Michelle

    Its nice article to start LINQ to XML.
    I found it is helpful to understand the Basic Xml operation using LINQ.

  7. SaiKumar Koya

    A Very Good Article :) Thanks A Lot For Sharing.

  8. Ralph Daudi

    Hello, thank you for posting a comprehensive article and the source code as well.
    However, i am facing a small problem, I created a new project based entirely on the source code you supply but when I run the application I get a “Object reference not set to an instance of an object.” exception when I attempt to get a list of all contacts.

    Please assist

    Thank You

  9. Joe

    Hi Ralph

    I can’t really give you an answer without know a bit more, or seeing the solution. Maybe upload your solution somewhere and I’ll have a look for you.

    Cheers
    Joe

  10. Ralph Daudi

    Hi Joe

    It is basically the same code as yours, but was trying to understand it by building from scratch – are you using Reflection for the Customer class?

  11. Joe

    Ralph

    It’s just a POCO. I can’t really help without knowing exactly where you are getting your exception or seeing the source code.

    Joe

  12. cipher0003

    Great example!! Thanks for sharing!! I wonder, that there is nothing comparable out there.
    I found very strange to see a copy of your article.
    Community means sharing and make it even better, not plain copying…….

  13. Noman A. Siddiqui

    Great Article…. Thanks Joe.

  14. Kapil

    Hi,

    Nice article, I am doing similar thing but i want to select the Phone based on Type (attribute)

    some thing like this

    XXX-XXX-XXXX
    XXX-XXX-XXXX

    So i can do the if inside the Select new Customer()
    {
    PhoneHome = ????
    }

    can you help me on that? Thanks

  15. Anand K Reddy

    Superab!!!

    It has made my job very easy to get started on Linq to xml.

    Thank you

  16. Piotr

    Hi i just used your class GetNextAvailableID() and when id reached 10, next avalible id was 2, i just delete FirstOrDefault from:
    select c.Attribute(“ID”).Value).FirstOrDefault()
    and it works fine, anyway this article help me a lot:) (I’m newbie to linqtoxml and c#)

  17. Kas

    Hi Joe,

    Thank you for this article. It was very helpful for me.

    Regards,
    Kas

  18. var

    Thanks. This was a great help.

    What would the save method look like, if each customer had a repeating sub element?

    <phones>
    <phone>555-1212</phone>
    <phone>555-1111</phone>
    <phone>555-2121</phone>
    </phones>

  19. Ian

    Is there a bug in the GetCustomers() method in the orderby clause? I reckon that “Surname” is an Element not an Attribute and I also reckon that you would have to tack a .Value onto the end.

    i.e. I think the orderby clause should be:
    orderby c.Element(“Surname”).Value

  20. Yehuda

    Excellent!
    Thank you.

  21. Ik0_a

    Good article to begin with.

    Thank !

  22. Pranshu

    Hi Joe,

    It was a nice post. I am new to Linq.
    However while tying your given code in POC (VS2010); I was geting null exception on below lines:
    c.Attribute(“ID”)Value.Equals(customerID.ToString())
    and
    c.Element(“Forename”).Value
    also on all similar lines.

    While debugging I was able to rectify the issue by replcaing it to:
    c.Element(“Customer”).Attribute(“ID”).Value.Equals(customerID.ToString())
    and
    c.Element(“Customer”).Element(“Forename”).Value

    I was confused to see so many comments on the post and none of us faced such issue.

    You can mail me for further clarification/information.

    Please correct me know in case I have missed out anything or interpreted wrongly.

    Regards,
    Pranshu

  23. Joe

    Hi Pranshu

    It’s difficult to say what your issue is without seeing all your code.

    Cheers
    Joe

  24. Thottijeya

    Useful article! You deserve lot of thanks for your spending time on helping us learn the basics of LINQ to XML. This article is a nice introduction to those who want to start learning LINQ to XML.

  25. Mangrish Naik

    It ws very helpful tutorial…..
    learned a lot 4m examples

  26. Jatin Chadarana

    Great Article for beginner….

  27. KinQ

    Awesome tutorial/example :)
    thanks a lot

  28. August Duet

    Thanks Joe, After several hours and some ugly code that only marginally worked this article cleared it all up for me. Keep it up.

  29. Charles

    Thanks for this post. Helped me a lot

  30. kellsie

    thanks a lots.good article for beginners.

  31. Rahul

    Thank you for taking the time to write such a clear and concise article on Linq to XML for the benefit of all.

  32. JOJY

    GOOD TUTORIAL FOR BEGINNERS…THANKS A LOT

  33. Snehal

    It is good.
    I am getting error, while updating the thing, data in xml file is getting updated but while fetching it again I am getting “Object reference not set to null”. Can anyone help?

  34. Joe

    Snehal

    Are you using the exact code from the post? Would need to see what line your getting the error on to give any help. Also, am assuming the error is ‘Object reference not set to an instance of an object”?

    It’s possible that the element your trying to access doesn’t exist.

    Joe

  35. Adeel Ahmed

    Excellent stuff.Lots of coverage in one round.Superb 10 out of 10

  36. Anand Gupta

    Good Article to begin with Linq to Xml

  37. Bhushan

    Good article to start with Linq to XML..Thank u!!

  38. shiva

    great article dude
    i have learnt lots of thing in xml using this article

  39. Andy

    This was JUST what I needed for one of my undergraduate degree modules, going to implement this later instead of a heavy, cumbersome SQL database, you explained the basic requirements for getting data out of an XML file perfectly.

    Thank you very much, bookmarked your site. :)

    Andy

  40. mrunmayee

    thank you soooooo much. :)

  41. mrunmayee

    hey,this is an awesome article ..thanks a lot

  42. ompc

    Hi;

    very very very very very very Useful;

    thank you;

  43. Meena Damwani

    Hi

    Awesome Article…

    It is very useful for beginners to learn linq to xml

  44. EXE

    :o) :o) :o) :o) :o) :o) :o) :o) :o) :o) :o) :o) :o) :o) :o)
    :o) muchas gracias señor, THANK YOU SO MUCH !! :o)
    :o) :o) :o) :o) :o) :o) :o) :o) :o) :o) :o) :o) :o) :o) :o)

  45. Pingback: Useful links on LINQ to XML, XML, ASP.NET MVC | Arnold Sia's space

  46. feng

    nice

Add a Comment