An Extensive Examination of LINQ: Introducing LINQ to XML
By Scott Mitchell
Introduction
XML is an increasingly popular way to encode documents, data, and electronic messages. There are a number of ways to programmatically create, modify, and search XML files. Since its inception, the .NET Framework's
System.Xml
namespace has included classes for programmatically working with XML documents. For instance, the XmlReader
and XmlWriter
classes offer developers a means to read from or write to
XML files in a fast, forward-only manner, while the XmlDocument
class
allows developers to work with an XML document as an in-memory tree representation.
LINQ to XML is a new set of XML-related classes in the .NET Framework (found in the
System.Xml.Linq
namespace), which enable developers to work with XML documents using
LINQ's features, syntax, and semantics. Compared to .NET's existing XML APIs, LINQ to XML is a simpler, easier to use API. For a given task, LINQ to XML code is typically shorter
and more readable than code that uses the XmlDocument
or XmlReader
/XmlWriter
classes. And perhaps most importantly, LINQ to XML allows
you to leverage your existing knowledge and familiarity with LINQ's standard query operators and query syntax.
This article is the first in a series of articles that examines LINQ to XML. This installment introduces the LINQ to XML API, examines some of the more pertinent classes
in the System.Xml.Linq
namespace, and shows how to perform a number of common XML tasks using the API. Read on to learn more!
XElement
- The LINQ to XML Workhorse
The most frequently used class in the LINQ to XML API is the
XElement
class,
which represents an XML element. This class is used when programmatically constructing an XML document, when loading an XML document, and when searching, filtering, or
otherwise enumerating the elements within an XML document.
For example, the XElement
class has a static Load
method,
which loads an XML document and returns the root of the just-loaded document as an XElement
object. The Load
method can be passed in the path to
an XML file on disk or the URL of an XML file online. You can also pass in a TextReader
or XmlReader
object.
The demo available for download at the end of this article includes an XML file in the App_Data
folder named Inventory.xml
. This XML file has a
root element named <inventory>
and then a variable number of <item>
elements. Each <item>
element represents an item
in inventory and contains children elements like <name>
, <unitPrice>
, and <quantity>
, among others. A snippet of this
XML file is shown below.
<?xml version="1.0" encoding="utf-8" ?>
|
The following code loads this XML file into an XElement
object. Keep in mind that we need to pass in the full path to the XML file to load
(for example, C:MySitesLINQDemosApp_DataInventory.xml
). To compute this path I use the Server.MapPath
method, which converts a virtual path (~/App_Data/Inventory.xml
)
into a physical path. For more information, see Using Server.MapPath
.)
// C# - Load the XML file Inventory.xml into an XElement object
|
The XElement
class includes a variety of properties and methods for working with the element's attributes and for working with the element's text value. There are
also methods for getting ancestor and descendant elements. The Value
property returns the concatenated text contents of the element and the text content of its descendants. For example, the Value
property of the xml
variable created in the above code snippet returns a string of all of the text content in the Inventory.xml
file (since xml
represents the root of the
XML file):
Blue Ball71114.95450Orange Octagon888814.95332Red Rhombus7001-RH5.5043...
|
Note that all of the text is concatenated. I've used varying colors to help disambiguate where one text element ends and the next begins.
Two other helpful members of the XElement
class are Elements
and Element
. The Elements
method returns all of the
child elements of the current element. You can optionally pass in an element name and then only those children element with a matching name are returned. The
Element
method requires a name as an input parameter and then returns the first child element with that name.
The following snippet shows these two methods in action. The example starts by enumerating through the children elements of the root element (namely, visiting each
<item>
element. For each <item>
element the <name>
and <unitPrice>
elements are grabbed via the
Element
method and their text values are read into a variable via their Value
properties:
// C# - enumerate through the root element's children elements
|
Understand that the Elements
method returns a collection of XElement
objects as type IEnumerable<XElement>
. As we've discussed
throughout this article series, LINQ is designed to work with collections of data of type IEnumerable<T>
. Consequently, we can use LINQ's standard
query operators and C# and Visual Basic's query syntax when working with LINQ to XML. The above loop can be rewritten using the query
syntax. The following demo shows using the query syntax to bind the name and price of each inventory item to a BulletedList control. The ASP.NET page contains a
BulletedList control named blInventoryItems
whose DataTextValue
property is set to "NameAndPrice". The query syntax code enumerates through each
<item>
element (via xml.Elements()
) and for each <item>
element it returns an object with a single string property named
NameAndPrice
that is assigned the value "Name (Price)".
// C#
|
The screen shot below shows the BulletedList control when viewed through a browser.

Creating XML
The
XElement
class can also be used to create XML content. One of the XElement
constructor overloads accepts as input a name for the element
and an array of objects that defines the element's content. This constructor can be used in a terse and human-readable format to programmatically generate XML content.
For instance, the following snippet of C# code programmatically creates XML content whose structure mirrors that of the Inventory.xml
file:
// C# - Create XML content
|
The above code is both terse and readable. You can determine the structure and contents of the XML being created by browsing the code. And things get even cooler if you are using Visual Basic, which supports XML literals. While you can certainly create XML content in VB using virtually identical syntax to that shown above, VB's XML literals allow for even more readable code. The following snippet creates the same XML content, but uses XML literals:
Dim inventoryXML As XElement = _
|
Modifying XML Content
The
XElement
class's SetAttributeValue
and
SetElementValue
methods are used to modifying attribute or
text values for an element. For example, the following code snippet doubles the price of every item in the Inventory.xml
file:
// C# - Double the price for each item in the inventory...
|
Here, xml
is the root element of the Inventory.xml
file. The above code starts by enumerating all of the root element's children via a foreach
loop. For each child, we get the <unitPrice>
value and then double it via a call to SetElementValue
. When this loop completes, each item in
the inventory will have had its <unitPrice>
value doubled.
Saving XML
Keep in mind that in the code snippets above any XML content created or modified via the
XElement
class's methods are in-memory changes. In other words, in
the preceding example where we doubled each price, that code does not actually modify the contents of the Inventory.xml
file. In other words, when we load
XML content via a call to XElement.Load(pathToXml)
, what's happening is that the XML content is being read from disk into an XElement
object in memory.
Any changes to that XElement
object - such as doubling the price - is a change made to that XElement
object in memory. The change is not
persisted back to the Inventory.xml
file unless we explicitly save the XML content back to disk.
To save XML content to disk use the XElement
class's Save
method.
You can pass this method a TextWriter
object, an XmlWriter
object, or a string that specifies the file path to where the content should be written.
The following snippet saves the contents of an XElement
to a file named XMLOutput.xml
in the same folder as the ASP.NET page that made this call.
XElementObject.Save(Server.MapPath("XMLOutput.xml"));
|
Returning to the double prices example, to save the doubled prices back to the Inventory.xml
file you could use C# code similar to the following.
(Download the demo available at the end of this article to see this code snippet in Visual Basic.)
// C# - Start by reading in the Inventory.xml contents
|
The demo available for download includes a web page named ModifyXML.aspx
that allows users to double or halve prices with the click of a button. The screen show
below shows the page's output immediately after the user has clicked the "Double Prices" button.

Looking Forward...
This article focused on the
XElement
object and techniques for creating, loading, and modifying XML content. We've only scratched the surface of the LINQ to XML
API, as we've yet to look at how to add and remove XML elements, how to deal with namespaces, how to do XML transforms, and how to perform standard LINQ operations against
XML, such as projections, filtering, aggregating, and so forth. These topics and more will be covered in future articles in this series.
Until then... Happy Programming!
Attachments:
Further Reading