LINQ to XML

LINQ offers an API called LINQ to XML, formally known as XLinq, that provides support for working with XML. This API resides in the System.Xml.Linq namespace, and you need to add a reference to the assembly with the same name to be able to use it. If you installed the Orcas March CTP bits, the assembly can be found in folder C:\Windows\Microsoft.NET\Framework\v3.5.20209.

In the namespace you can find classes such as XNode, XElement, XAttribute, XText, etc.

XElement implements an XML element. It has several constructor. The following snippet constructs an empty element called winner.

   XElement root = new XElement("winner");
   Console.WriteLine(root.ToString());


The output is

< winner />


Overloaded constructor can take additional parameters. If we pass a string:

XElement root = new XElement("winner", "Manchester Utd.");


We get:

< winner >Manchester Utd.< /winner >


We can also pass an Xattribute

XElement root = new XElement("winner", "Manchester Utd.",
                             new XAttribute("Year", 1999));


Or

XElement root = new XElement("winner", new XAttribute("Year", 1999),
                             "Manchester Utd.");


In this case the winner element will have an attribute called Year having the value 1999, and the text of the element will be Manchester Utd..

< winner Year="1999" >Manchester Utd.< /winner >


We can nest the all these to make a hierarchy of xml elements:

XElement root = new XElement("winners",
                              new XElement("winner",
                                   new XElement("Name", "Barcelona"),
                                   new XElement("Country", "Spania"),
                                   new XElement("Year", 2006)
                              ),
                              new XElement("winner",
                                   new XElement("Name", "Liverpool"),
                                   new XElement("Country", "Anglia"),
                                   new XElement("Year", 2005)
                              )
                );


Of course, the XML elements don’t have to be created like that. They can be dynamically created. One way is using methods like Add, AddFirst, RemoveNodes, etc., methods from the XContainer class.

IEnumerable< Winner > winners = UCL.GetWinners();
XElement root = new XElement("winners");

foreach (Winner w in winners)
{
      root.Add(new XElement("winner",
                             new XElement("Name", w.Name),
                             new XElement("Country", w.Country),
                             new XElement("Year", w.Year)));
}


And we can write this to a file with:

Root.Save("winners.xml");


However, LINQ to XML offers a better way to generate XML content.

IEnumerable< Winner > winners = UCL.GetWinners();

XElement root = new XElement("winners", 
                    from w in winners
                    select new XElement("winner",
                                        new XElement("Name", w.Name),
                                        new XElement("Country", w.Country),
                                        new XElement("Year", w.Year)));  

The result in this case is the same as above.

XElements has several overloads for saving its content to a file:

public void Save(string fileName);
public void Save(TextWriter textWriter);
public void Save(XmlWriter writer);
public void Save(string fileName, bool preserveWhitespace);
public void Save(TextWriter textWriter, bool preserveWhitespace);


On the other hand, XElement offers several overloaded static methods for loading content from XML files:

public static XElement Load(string uri);
public static XElement Load(TextReader textReader);
public static XElement Load(XmlReader reader);
public static XElement Load(string uri, bool preserveWhitespace);
public static XElement Load(TextReader textReader, bool preserveWhitespace);
public static XElement Parse(string text);
public static XElement Parse(string text, bool preserveWhitespace);


The following code loads the content of the file winners.xml and prints it in the console.

XElement root = XElement.Load("winners.xml");
Console.WriteLine(root.ToString());


Considering that we have in winners.xml the list of UEL winners, we can load the content of this XML file and create Winner objects:

IEnumerable< Winner > winners =
             from e in XElement.Load("winners.xml").Elements("winner")
             select new Winner
                    {
                         Name = (string)e.Element("Name"),
                         Country = (string)e.Element("Country"),
                         Year = (int)e.Element("Year")
                    };

foreach (Winner w in winners)
{
     Console.WriteLine("{0} {1}, {2}", w.Year, w.Name, w.Country);
}


XElement.Load() creates an XElement containing all the elements in the file. Elements() returns only the children called winner (in our case all the children elements of the root). After that we project Winners created by accessing the children of element “winner” in the XML file. The output is

2006 Barcelona, Spania
2005 Liverpool, Anglia
2004 FC Porto, Portugalia
2003 AC Milan, Italia
2002 Real Madrid, Spania
2001 Bayern Munchen, Germania
2000 Real Madrid, Spania
1999 Manchester Utd., Anglia
1998 Real Madrid, Spania
1997 Borussia Dortmund, Germania
1996 Juventus, Italia
1995 AFC Ajax, Olanda
1994 AC Milan, Italia
1993 Olympique de Marseille, Franta


Now suppose you want to project only the names of the winners. In this case we could write:

var winners =
            from e in XElement.Load("winners.xml").Elements("winner")
            select (string)e.Element("Name");

foreach (var w in winners)
{
     Console.WriteLine("{0}", w);
}


The ouput of the program is:

Barcelona
Liverpool
FC Porto
AC Milan
Real Madrid
Bayern Munchen
Real Madrid
Manchester Utd.
Real Madrid
Borussia Dortmund
Juventus
AFC Ajax
AC Milan
Olympique de Marseille


This output however lists a team multiple times. If we want to have these winners listed only once we could apply the Distinct operator on the result and select the winners only once:

var winners =
         from e in XElement.Load("winners.xml").Elements("winner")
         select (string)e.Element("Name");

var winnersDistinct = Enumerable.Distinct(winners);

foreach (var w in winnersDistinct)
{
    Console.WriteLine("{0}", w);
}


The new output would be

Barcelona
Liverpool
FC Porto
AC Milan
Real Madrid
Bayern Munchen
Manchester Utd.
Borussia Dortmund
Juventus
AFC Ajax
Olympique de Marseille


Hits for this post: 24389 .
Trackback

only 1 comment untill now

  1. Gravatar

    Thanks for sharing, I had been wondering about this and your code really helped.

Add your comment now