Find Next or Previous XML Elements Using LINQ C# and Vb.Net

← PrevNext →

Let me show you how to traverse through an XML document using LINQ in Asp.Net. LINQ provides properties that are useful to navigate through various elements in an XML document. Like a database, you can fetch values in an XML doc traversing through the next or previous elements (or nodes). The two LINQ properties, which I’ll use in my example, are property NextNode and property PreviousNode.

I have two button controls on my web page to do the next and previous operations on the XML doc. The button’s click event will call the code behind procedures to execute the navigation. However, first we need an XML doc.

My XML
<?xml version="1.0"?>
<!--   Last edited by https://encodedna.com   -->
<Library>
  <List>
    <BookName>Computer Architecture</BookName>
    <Category>Computers</Category>
    <Price>125.60</Price>
  </List>
  <List>
    <BookName>Advanced Composite Materials</BookName>
    <Category>Science</Category>
    <Price>172.56</Price>
  </List>
  <List>
    <BookName>Asp.Net 4 Blue Book</BookName>
    <Category>Programming</Category>
    <Price>56.00</Price>
  </List>
  <List>
    <BookName>Stategies Unplugged</BookName>
    <Category>Science</Category>
    <Price>99.99</Price>
  </List>
</Library>

Get complete XML data here. Library.xml

The Markup
<body>
    <div>
        <div style="width:300px">
            <p style="text-align:center;"><label id="lblXML" runat="server"></label></p>
            
            <div>
                <button class="btprevnext" style="float:right;" 
                    id="btnext" onserverclick="next_art" runat="server">Next</button>
            </div>
            <div>
                <button class="btprevnext" style="float:left;" 
                    id="btprev" onserverclick="previous_art" runat="server">Previous</button>
            </div>
        </div>
    </div>
</body>

When the page loads for the first time, I’ll show the first elements value in the label. In addition, I’ll store the BookName value in a ViewState, so I can use it later to find either the next or previous value.

Code behind (C#)
using System;
using System.Collections.Generic;
using System.Web;

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

protected void Page_Load(object sender, System.EventArgs e)
{
    // SHOW THE FIRST ELEMENT'S VALUES.

    if (!IsPostBack) {
        lblXML.InnerHtml = "";      // CLEAR THE LABEL.

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

        XElement result = 
            (from xFi in xml_Doc.Descendants("List")
                select xFi).FirstOrDefault();

        if ((result != null)) {
	        lblXML.InnerHtml = 
                "<b> Name: </b>" + result.Element("BookName").Value + "<br />" + 
                "<b> Category: </b> " + result.Element("Category").Value + "<br />" + 
                "<b> Price: </b>" + result.Element("Price").Value;

	        ViewState["selectedBook"] = result.Element("BookName").Value;
        } else {
	        lblXML.InnerHtml = "Found Nothing";
        }
    }
}

protected void next_art(object sender, EventArgs e)
{
    navigateXML("next");
}

protected void previous_art(object sender, EventArgs e)
{
    navigateXML("previous");
}

private void navigateXML(string sGo)
{
    // LOAD XML DOCUMENT.
    var xml_Doc = XDocument.Load(Server.MapPath("library.xml"));

    string sSelected_Value = ViewState["selectedBook"].ToString();

    // SEARCH XML USING THE SELECTED VALUE.
    XElement search_result = 
        (from xFi in xml_Doc.Descendants("List")
            where xFi.Element("BookName").Value.ToUpper() == sSelected_Value.ToUpper()
        select xFi).FirstOrDefault();

    if ((search_result != null)) {
	    
        XElement node = null;

        // NAVIGATE XML DOCUMENT USING "NextNode" OR "PreviousNode".
        // HOWEVER, FIRST WE HAVE TO CAST "NextNode" OR "PrevioueNode" to XElement TO GET A VALUE.
        if ((sGo) == "next") {
            node = (XElement)search_result.NextNode;                    // NEXT NODE.
        } else if ((sGo) == "previous") {
            node = (XElement)search_result.PreviousNode;                // PREVIOUS NODE.
        }

        // CHECK IF WE HAVE REACHED THE LAST OR FIRST NODE.
        if ((node != null)) {

	        lblXML.InnerHtml = "";		        // CLEAR THE LABEL FOR NEW VALUES.

            // ASSIGN VALUE TO A VIEWSTATE, SO WE CAN USE THE VALUE LATER.w
	        ViewState["selectedBook"] = node.Element("BookName").Value;

	        IEnumerable<XElement> search_new_value = null;

            // NOW, GET VALUES FOR THE NEWLY EXTRACTED BOOKNAME.
            search_new_value = 
                (from xFi in xml_Doc.Descendants("List")
                    where xFi.Element("BookName").Value.ToUpper() == 
                        ViewState["selectedBook"].ToString().ToUpper()
                    select xFi);
                
            foreach (XElement result in search_new_value) {
                lblXML.InnerHtml = lblXML.InnerHtml + 
                    "<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";
    }
}
Vb.Net
Option Explicit On

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
            lblXML.InnerHtml = ""       ' CLEAR THE LABEL.

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

            Dim result As XElement = _
                (From xFi In xml_Doc.Descendants("List") _
                 Select xFi).FirstOrDefault()

            If Not result Is Nothing Then
                lblXML.InnerHtml = _
                    "<b> Name: </b>" & result.Element("BookName").Value & "<br />" & _
                    "<b> Category: </b> " & result.Element("Category").Value & "<br />" & _
                    "<b> Price: </b>" & result.Element("Price").Value

                ViewState("selectedBook") = result.Element("BookName").Value
            Else
                lblXML.InnerHtml = "Found Nothing"
            End If
        End If
    End Sub

    Protected Sub next_art(ByVal sender As Object, ByVal e As EventArgs)
        navigateXML("next")
    End Sub

    Protected Sub previous_art(ByVal sender As Object, ByVal e As EventArgs)
        navigateXML("previous")
    End Sub

    Private Sub navigateXML(ByVal sGo As String)

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

        Dim sSelected_Value As String = Trim(ViewState("selectedBook"))

        ' SEARCH XML USING THE SELECTED VALUE.
        Dim search_result As XElement = _
            (From xFi In xml_Doc.Descendants("List") _
             Where UCase(xFi.Element("BookName").Value) = UCase(sSelected_Value)
             Select xFi).FirstOrDefault()

        If Not search_result Is Nothing Then
            Dim node As XElement = Nothing

            ' NAVIGATE XML DOCUMENT USING "NextNode" OR "PreviousNode".
            If (sGo) = "next" Then
                node = search_result.NextNode             ' NEXT NODE.
            ElseIf (sGo) = "previous" Then
                node = search_result.PreviousNode         ' PREVIOUS NODE.
            End If

            If Not node Is Nothing Then  ' CHECK IF WE HAVE REACHED THE LAST OR FIRST NODE.             

                lblXML.InnerHtml = ""               ' CLEAR THE LABEL FOR NEW VALUES.
                ViewState("selectedBook") = node.Element("BookName").Value

                Dim search_new_value As IEnumerable(Of XElement)

                search_new_value = _
                    (From xFi In xml_Doc.Descendants("List") _
                     Where UCase(xFi.Element("BookName").Value) = 
                        UCase(ViewState("selectedBook"))
                     Select xFi)

                For Each result As XElement In search_new_value
                    lblXML.InnerHtml = lblXML.InnerHtml & _
                        "<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
            End If
        Else
            lblXML.InnerHtml = "Found Nothing"
        End If
    End Sub
End Class

Property NextNode

Traverse forward through an XML document using the property NextNode. This property will extract and return next node’s values for the selected node. However, if there is no next node, it will return null.

For example, if the select node has this value, <BookName>Asp.Net 4 Blue Book</BookName>, then it will NextNode property will return the immediate next node, which is this value, <BookName>Stategies Unplugged</BookName>. See the XML document above that I have shared.

Property PreviousNode

The PreviousNode property traverses backward through the XML document. It will extract previous node’s value for the selected node.

← PreviousNext →