LINQ To XML And Why You Need To Know It

Short introduction to LINQ to XML

In .NET 3.5, the primary device for general processing of XML is LINQ To XML. This provides a lightweight, LINQ-friendly DOM along with a set of query operators.

In SiIlverlight, this is your only choice - XmlDocument and related classes are not supported. Even without its LINQ support, the LINQ To XML DOM is valuable as an easy – to – use facade over the XmlReader / Writer classes.

All of the LINQ To XML types are defined in the System.Xml.Linq namespace.

The LINQ To XML DOM, or “X-DOM” consists of types like XDocument, XElement, and XAttribute. All of the methods are “LINQ – friendly” in that they emit IEnumerable sequences on which you can query. The constructors are designed so that you can build an X-DOM tree through a LINQ projection.

For example, this LINQ To SQL query projects directly into an X-DOM:

XElement xml = new XElement("contacts",
from c in db.Contacts
orderby c.ContactId
select new XElement("contact",
new XAttribute("contactId", c.ContactId),
new XElement("firstName", c.FirstName),
new XElement("lastName", c.LastName))
);

XElement is the most frequently used class. XDocument represents the root of an XML tree; it wraps the root XElement with an XDeclaration, processing instructions,and other root-level items. However, its use is optional – you can load, manipulate and save an X-DOM without creating an XDocument.

XElement and XDocument offer static Load and Parse methods. Load builds an X-DOM through a file, URL, TextReader, or an XmlReader. Parse builds an X-DOM from a string.

Examples:

XDocument fromRss = XDocument.Load( “http://www.eggheadcafe.com/rss.xml”);
(In SIlverlight, this method only works with relative urls)

XElement fromSettings = XElement..Load(“C:\MyProject\web.config”);

XElement person = XElement.Parse( @”<Person>
<FirstName>John</FirstName>
<LastName>Rogers</LastName>
</Person>”);

XNode provides a static ReadFrom method that can instantiate and populate any type of node from an XmlReader. It stops after reading one complete node so you can continue to read nodes manually from the XmlReader.

You can also use an XmlReader or XmlWriter to read and write an XNode via its CreateReader and CreateWriter methods.

If you call ToString on any Node, this converts its content to an XML string formatted with line breaks and indentation.

XElement and XDocument also have a Save method that writes an X-DOM to a file, TextWriter or XmlWriter. WIth a file, the declaration is written automatically. There is also a WriteTo method in XNode that accepts an XmlWriter.

Here is an example of how one might use a LINQ To XML query to populate a Silverlight ListBox containing a StackPanel, directly from a consumed RSS feed:

namespace RSS
{
public class RssItem
{
public string Title { get; set; }
public string Description { get; set; }
public string Link { get; set; }
public string PubDate { get; set;}
}
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
WebClient wc = new WebClient();
wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
wc.DownloadStringAsync(new Uri("http://www.eggheadcafe.com/rss.xml"));
}

void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
XElement rss= XElement.Parse(e.Result);
var items = from item in rss.Descendants("item")
select new RssItem()
{
Title = item.Element( "title").Value,
Description = item.Element("description").Value,
Link =item.Element("link").Value,
PubDate = item.Element("pubDate").Value
};
FeedList.ItemsSource = items.ToList();
}
}
}

And the XAML:

<UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" x:Class="RSS.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<Grid x:Name="LayoutRoot" Width="400" Height="400">
<ListBox x:Name="FeedList" Width="400" Height="400" Visibility="Visible">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="Stack1" Orientation="Vertical" Visibility="Visible">
<HyperlinkButton Width="400" Height="24" FontFamily="Arial" NavigateUri="{Binding Link}" Content="{Binding Title}" />
<TextBlock Width="400" Height="24" FontFamily="Arial" FontWeight="Bold" Foreground="Black" Text="{Binding Description}" TextWrapping="Wrap" />
<TextBlock Width="400" Height="24" FontFamily="Arial" Text="{Binding PubDate}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</UserControl>

Interestingly, the above example will not work with anonymous types (e.g. select new { Title =.... ). You need to define a nominal container class (RssItem, above) in order for databinding to Silverlight controls to work.

Various LINQ operators can be combined and chained to provide specific filtering similar to the WHERE, ORDER BY, AND JOIN clauses (among others) in a SQL query, giving the developer great flexibility once these techniques are mastered.

Navigation is accomplished through a set of Properties on the XNode object, such as Parent, AncestorXXX, and others. Intellisense will provide a rich list of choices to choose from and experiment with; all you need to do is type a “.” dot after an XElement / XNode variable to see the list.

There is much more to LINQ To XML and using LINQ with XElement. This short article can only provide a small introduction. Some good resources for learning LINQ to XML are:

“C# 3.0 In a Nutshell” (Albahari brothers)
LINQPAD by the same authors (Recommended free download)
LINQ to XML MSDN Documentation
”Hooked on LINQ” 5 minute overview
"LINQ In Action"  - Manning

Spend some time getting used to LINQ To XML. It will serve you well going forward.

By Peter Bromberg   Popularity  (5337 Views)