Conditional XML Element Selection using LINQ to XML Filtering Features Using LINQ WHERE Clause in C# and Vb.Net

← PrevNext →

Any discussion on LINQ to XML is incomplete without mentioning one of its most interesting features, that is, the Conditional Element Selection or filtering data using the LINQ WHERE clause. If you are familiar with basic SQL conditionings, such as, a "where" clause to filter data from a table, then I am sure you it would not bother you much. Here, in this article I’ll show you how to filter XML elements using LINQ to XML where clause.

Scenario

I have data in an XML document and its big. I know the document has a list of books (an "inventory" of books) with important details about each book. I would like to use LINQ and its condition features, such as, the "where" clause, to filter XML elements based on a search value.

For example, I would enter the name of the book and I get the details about the book, instantly. For multiple results, I would enter a category (books category), such as, science and it would return all elements with the category science.

I have previously written an article, where I have explained with examples about how to load and read an XML document (all the elements and child elements, without filtering) using LINQ to XML. I am mentioning about the article, since I have borrowed few snippets from the examples, also the structure of the XML.

Here is the sample XML document.

Library.xml

Now, lets get on with this article.

I have divided this article into two sections. In the first section, I’ll show you how to set condition using where clause to filter a single XML element and read the values in it.

Second, using a similar principle, I’ll filter and read multiple XML elements by providing a value to the “where” clause and display the result. In the multiple selections, however, I have run a loop to read all the elements and its values.

* Single Conditional XML Element Selection in LINQ to XML

In the markup section, I have added few controls, such as, an <input> element of type text, to enter the search value and another <input> element of type button.

The Markup
<div>
    <p>
        <label>Enter a value to search:</label>
        <input type="text" id="tbBook" runat="server" />
    </p>
    <p>
        <input type="button" id="bt" value="Search" runat="server" 
            onserverclick="find_my_book" />
    </p>

    <p><label id="lblXML" runat="server"></label></p>
</div>
Code Behind (C#)
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using System.Linq;                  // FOR Descendants().
using System.Xml.Linq;              // FOR XDoument, XElement.

public partial class SiteMaster : System.Web.UI.MasterPage
{
    protected void find_my_book(object sender, EventArgs e)
    {

        lblXML.InnerHtml = "";          // CLEAR THE LABEL.

        // LOAD XML DOCUMENT.
        var xml_Doc = XDocument.Load(Server.MapPath("library.xml"));

        var sSearch_Value = tbBook.Value.ToString();
        
        // SEARCH XML USING A CONDITION.

        XElement search_result =
            (from xFi in xml_Doc.Descendants("List")
                where xFi.Element("BookName").Value.ToUpper() == sSearch_Value.ToUpper()
                select xFi).FirstOrDefault();

        if ((search_result != null))
        {
            lblXML.InnerHtml = 
                "<b> Name: </b>" + search_result.Element("BookName").Value + "<br />" + 
                "<b> Category: </b> " + search_result.Element("Category").Value + "<br />" + 
                "<b> Price: </b>" + search_result.Element("Price").Value;
        }
        else
        {
            lblXML.InnerHtml = "Found Nothing";
        }
    }
}
Vb.Net
Option Explicit On

Partial Class Site
    Inherits System.Web.UI.MasterPage

    Protected Sub find_my_book(ByVal sender As Object, ByVal args As EventArgs)

        lblXML.InnerHtml = ""       ' CLEAR THE LABEL.

        If Trim(tbBook.Value) <> "" Then

            ' LOAD XML DOCUMENT.
            Dim xml_Doc = XDocument.Load(Server.MapPath("library.xml"))

            Dim sSearch_Value As String = Trim(tbBook.Value)

            ' SEARCH XML USING A CONDITION.
            Dim search_result As XElement = _
                (From xFi In xml_Doc.Descendants("List") _
                 Where UCase(xFi.Element("BookName").Value) = UCase(sSearch_Value)
                 Select xFi).FirstOrDefault()

            If Not search_result Is Nothing Then
                lblXML.InnerHtml = _
                    "<b> Name: </b>" & search_result.Element("BookName").Value & "<br />" & _
                    "<b> Category: </b> " & search_result.Element("Category").Value & "<br />" & _
                    "<b> Price: </b>" & search_result.Element("Price").Value
            Else
                lblXML.InnerHtml = "Found Nothing"
            End If
        End If
    End Sub
End Class

* Multiple Conditional XML Element Selection in LINQ to XML

I am not repeating the markup for this example, as remains the same. Simply follow the code behind procedures.

Code Behind (C#)
protected void find_my_book(object sender, EventArgs e)
{
    lblXML.InnerHtml = "";          // CLEAR THE LABEL.

    // LOAD XML DOCUMENT.
    var xml_Doc = XDocument.Load(Server.MapPath("library.xml"));

    var sSearch_Value = tbBook.Value.ToString();
       
    // SEARCH MULTIPLE XML ELEMENTS USING "where" CLAUSE.
    IEnumerable<XElement> search_result = null;
    search_result =
            from xFi in xml_Doc.Descendants("List")
            where xFi.Element("Category").Value.ToUpper() == sSearch_Value.ToUpper()
            select xFi;

    if ((search_result != null))
    {
        if (search_result.Count() > 0)
        {
            foreach (XElement result in search_result)
            {
                lblXML.InnerHtml = lblXML.InnerHtml + "<br />" +
                    "<b> Book Name: </b>" + result.Element("BookName").Value + "<br />" +
                    "<b> Category: </b> " + result.Element("Category").Value + "<br />" +
                    "<b> Price: </b>" + result.Element("Price").Value + "<br />";
            }
        }
        else
        {
            lblXML.InnerHtml = "Found Nothing";
        }
    }
    else
    {
        lblXML.InnerHtml = "Found Nothing";
    }
}
Vb.Net
Protected Sub find_my_book(ByVal sender As Object, ByVal args As EventArgs)

    lblXML.InnerHtml = ""       ' CLEAR THE LABEL.

    If Trim(tbBook.Value) <> "" Then

        ' LOAD XML DOCUMENT.
        Dim xml_Doc = XDocument.Load(Server.MapPath("library.xml"))

        Dim sSearch_Value As String = Trim(tbBook.Value)


        ' SEARCH MULTIPLE XML ELEMENTS USING "where" CLAUSE.
        Dim search_result As IEnumerable(Of XElement)
        search_result = _
            (From xFi In xml_Doc.Descendants("List") _
                Where UCase(xFi.Element("Category").Value) = UCase(sSearch_Value)
                Select xFi)

        If Not search_result Is Nothing Then
            If search_result.Count > 0 Then
                For Each result As XElement In search_result

                    lblXML.InnerHtml = lblXML.InnerHtml & "<br />" & _
                        "<b> Book Name: </b>" & result.Element("BookName").Value & "<br />" & _
                        "<b> Category: </b> " & result.Element("Category").Value & "<br />" & _
                        "<b> Price: </b>" & result.Element("Price").Value & "<br />"
                Next
            Else
                lblXML.InnerHtml = "Found Nothing"
            End If
        Else
            lblXML.InnerHtml = "Found Nothing"
        End If
    End If
End Sub
Conclusion

Its an interesting piece of information and code. Let me explain what this article has for you. In the beginning, I have explained a small scenario and accordingly I have written codes to first filter a single XML element, by providing a value as condition in the “where” clause. Second, the code returns multiple XML elements, based on a certain condition.

I want you to notice, one important piece of method inside the code. I have used C# “toUpper()” method (UCase() method for Vb.Net). Please remember, that the values are case-sensitive.

← PreviousNext →