n Part 1 of this article series, you looked at XLinq’s ability to create, modify, and delete XML data. Building on that background, this installment focuses on XLinq’s query features, by first delving into the standard query operators supplied with LINQ and then providing examples of using them to query XML data. Finally this article will also provide an example of transforming XML data to a collection using the new LINQ query format.
Querying XML
The main goal of the LINQ family of technologies is to add general purpose query facilities to the .NET Framework so that you can query all sources of information (including the relational and XML data) through a unified query approach. Because of the generic query foundation, you can apply LINQ to query any class as long as that class implements IEnumerable
XLinq is an XML query language that inherits from the LINQ query foundation. You can use it to query XLinq objects such as XElement, XDocument, etc using LINQ query facilities.
Performing a Simple Query
Here’s a simple XML file called Products.xml (available with the downloadable sample code) that I’ve used as the source document for the query capabilities described in this article:
Adjustable Race AR-5381 Bearing Ball BA-8327 BB Ball Bearing BE-2349 LL Crankarm CA-5965 Number="" /> ML Crankarm CA-6738 ML Crankarm CA-6738
The Products.xml file is a simple product list where each product consists of an id, name, and number. To query this file with XLinq, first create an ASP.NET page named SimpleXLinqQuery.aspx, and then set the page’s contents as shown below:
<%@ Page Language="C#" %> <%@ Import Namespace="System.Data.DLinq" %> <%@ Import Namespace="System.Data.SqlClient" %> <%@ Import Namespace="System.Xml.XLinq" %> <%@ Import Namespace="System.Expressions" %> <%@ Import Namespace="System.Query" %> <%@ Import Namespace="System.Web.Configuration" %> Simple XLinq Query
At the top of the page, you can see import statements for all the required namespaces. One key namespace is System.Query, which contains a number of powerful classes that provide native querying capabilities. This example shows how to return all the product names in the Products.xml file.
Add a button control and a GridView control to your ASP.NET page. In the Click event code for the button, start by loading the XML file into memory using the Load() method of the XElement class.
XElement products = XElement.Load(Server.MapPath ("~/App_Data/Products.xml"));
After loading the XML file, the next step is to retrieve all the product names.
var productNames = from prod in products.Elements("Product") orderby (string) prod.Element("Name") select (string) prod.Element("Name");
The preceding line of code does the majority of the work. Here’s a more detailed examination.
![]() |
? |
Figure 1. Product Names Output: Here’s the output of the SimpleXLinqQuery.aspx example, showing the list of product names retrieved from the Products.xml file. |
The var keyword signals the compiler that you are using the new local variable Type Inference feature in .NET Framework 3.0. This var keyword differs from the JavaScript var keyword (which creates a variable capable of holding any type of data) in that it tells the C# compiler to infer the type from the assignment of values. As an example, if you assign “1” to a variable of type var, the compiler will infer the type of that variable to be int
On the right side of the equals sign, the code uses a from..select syntax to query the XML file. This statement selects all
Once you have the list of product names, you can easily bind it to a GridView by setting the DataSource property (see Figure 1).
gridResult.DataSource = productNames; gridResult.DataBind();
Using the “where” Operator
Beyond the basic query operators you just saw, XLinq has operators such as the important where operator that lets you filter query results based on supplied criteria. To demonstrate this, add a text box named txtValue and a button named btnGetProductNameForID to the page. As the name of the button suggests, clicking this button retrieves the product name for a specific product ID. The Click event code for the new button looks like this:
![]() |
? |
Figure 2. Displaying a Product Name for a Specific Product ID: In this example, when a users enters a product ID and clicks the button, the application returns the corresponding product name. |
void btnGetProductNameForID_Click (object sender, EventArgs e) { XElement products = XElement.Load (Server.MapPath ("~/App_Data/Products.xml")); var productNames = from prod in products.Elements("Product") where (string)prod.Attribute("ID") == txtValue.Text select (string) prod.Element("Name"); gridResult.DataSource = productNames; gridResult.DataBind(); }
In this example, when a user enters a product ID into the txtValue text field, and clicks button, the “where” operator selects the product name that matches the supplied product ID. Figure 2 shows the example in action.
Using the “Take” Operator
Similar to the where operator, the Take operator provides you with a way to select all the elements before some supplied position. For example, the following code snippet shows how to select the first five product names from the Products XML file.
Author’s Note: Although the syntax for the “where” operator is different from the “Take” operator?which is obviously a method?the documentation refers to both as “operators,” so I have followed that lead in the terminology used for this article. |
void btnGetTop5ProductNames_Click (object sender, EventArgs e) {
? Figure 3. Filtering the First Five Product Names: Here's the page in a browser, displaying the first five product names from the products list.
XElement products = XElement.Load (Server.MapPath ("~/App_Data/Products.xml")); var productNames = (from prod in products.Elements("Product") orderby (string) prod.Element("Name") select (string) prod.Element("Name")).Take(5); gridResult.DataSource = productNames; gridResult.DataBind(); }
I won’t go through the full description of how to set up an example page, but you can easily see what’s involved by looking at Figure 3.
Note how adding the Take operator at the end of the query simply changes the output returned by the query. This just shows the power of LINQ as a query language.
Similarly, you can also get the unique list of product names using the Distinct operator.
var productNames = (from prod in products.Elements("Product") orderby (string) prod.Element("Name") select (string)prod.Element ("Name")).Distinct();
The Distinct operator eliminates duplicate product names from the resultant output. In addition to the Where, Take, and Distinct operators shown so far, LINQ exposes a number of other operators, the most important of which are shown in Table 1.
Table 1. Standard Query Operators: The table shows common query operators used for querying objects that are based on IEnumerable
Operator | Description |
select | Specifies the return value for the query. |
where | Allows you to filter the output. |
First | Retrieves the first member from the resultant list. |
ElementAt | Allows you to access the specific member at specified position. |
Take | Accesses the members before the specified position. |
Skip | Accesses the members after the specified position. |
ToDictionary | Allows you to return the results in a key pair value list. |
orderby | Allows sorting of the resultset in ascending order. |
orderbyDescending | Allows sorting of the resultset in descending order. |
Reverse | Allows you to reverse the order of sequence. |
Distinct | Allows you to filter duplicate members. |
ToList | Allows you to return the results as a list represented by List |
Except | Allows you to filter elements that are members of a specific set. |
Transforming XML with XLinq
So far, you’ve seen how to query the XML file using query operators, but sometimes you might want to query the XML and transform the results directly into objects that you can then pass to other applications or services for further processing. With XLinq, converting XML to objects is a breeze, often requiring only a single line of code.
To demonstrate this, I’ll show you how to query the Products.xml file and transform its contents into a collection of ProductInfo objects that are then bound to a GridView control. Listing 1 shows the complete code for the page, but here’s the interesting portion. First, to retrieve all the
var productInfos = from prod in products.Descendants("Product") orderby (string) prod.Element("Name") select new ProductInfo { ProductID = (int)prod.Attribute("ID"), ProductName = (string)prod.Element("Name"), ProductNumber = (string)prod.Element("Number") };
After you have all the
As you can probably guess, the ProductInfo class used in the preceding example is very simple. It exposes three public properties: ProductID, ProductName, and ProductNumber.
using System; public partial class ProductInfo { private int _productID; private string _productName; private string _productNumber; public ProductInfo(){} public int ProductID { get{return _productID;} set{_productID = value;} } 
? Figure 4. XML-to-object Conversion: Here's the output produced by converting the products XML data to a ProductInfo collection and binding that to a GridView Control.
public string ProductName { get{return _productName;} set{_productName = value;} } public string ProductNumber { get{return _productNumber;} set{_productNumber = value;} } }
Place the ProductInfo class in the App_Code directory of your project, and then navigate to the page using the browser. You’ll see the output shown in Figure 4.
In this installment of the XLinq series, you’ve seen how to use the standard LINQ query operators to select, and filter XML data, as well as how to transform XML data into a strongly-typed collection. The next installment focuses on using DLinq (LINQ to SQL) in conjunction with XLinq to retrieve relational data, transform it to XML data, and vice versa.