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.