Archive
Using LINQ to parse XML
LINQ is cool. Using LINQ to parse XML is cool. I will show you how to use LINQ to parse XML and build a list of objects (I know I can use XML serialization/deserialization to do the same thing, but this is just a demonstration).
Here is my two XML files:
(1) member01.xml
1 <?xml version=“1.0“ encoding=“utf-8“ ?>
2 <Members>
3 <Member>
4 <MemberId>1</MemberId>
5 <Name>Marlon Brando</Name>
6 <Character>Don Vito Corleone</Character>
7 <IMDBLink>http://www.imdb.com/name/nm0000008/</IMDBLink>
8 </Member>
9 <Member>
10 <MemberId>2</MemberId>
11 <Name>Al Pacino</Name>
12 <Character>Michael Corleone</Character>
13 <IMDBLink>http://www.imdb.com/name/nm0000199/</IMDBLink>
14 </Member>
15 <Member>
16 <MemberId>3</MemberId>
17 <Name>James Caan</Name>
18 <Character>Santino ‘Sonny’ Corleone</Character>
19 <IMDBLink>http://www.imdb.com/name/nm0001001/</IMDBLink>
20 </Member>
21 </Members>
(2) member02.xml
1 <?xml version=“1.0“ encoding=“utf-8“ ?>
2 <Members>
3 <Member>
4 <MemberId>1</MemberId>
5 <Name>Marlon Brando</Name>
6 <Character>Don Vito Corleone</Character>
7 <IMDBLink>http://www.imdb.com/name/nm0000008/</IMDBLink>
8 </Member>
9 <Member>
10 <MemberId>2</MemberId>
11 <Name>Al Pacino</Name>
12 <Character>Michael Corleone</Character>
13 <IMDBLink>http://www.imdb.com/name/nm0000199/</IMDBLink>
14 </Member>
15 <Member>
16 <MemberId>3</MemberId>
17 <Name>James Caan</Name>
18 <Character>Santino ‘Sonny’ Corleone</Character>
19 <IMDBLink>http://www.imdb.com/name/nm0001001/</IMDBLink>
20 </Member>
21 <Member>
22 <MemberId>4</MemberId>
23 <Name>Robert Duvall</Name>
24 <Character>Tom Hagen</Character>
25 </Member>
26 </Members>
As you can see in the member02.xml, the last member does not have <IMDBLink> element.
I build an entity class to represent the member object:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Web;
5 using System.Text;
6
7 namespace FrameworkTestBed
8 {
9 [Serializable]
10 public class Member
11 {
12 public int MemberId { get; set; }
13 public string Name { get; set; }
14 public string Character { get; set; }
15 public string IMDBLink { get; set; }
16
17 public override string ToString()
18 {
19 StringBuilder sb = new StringBuilder();
20 sb.Append(string.Format(“MemberId: {0}, “, MemberId));
21 sb.Append(string.Format(“Name: {0}, “, Name));
22 sb.Append(string.Format(“Character: {0}, “, Character));
23 sb.Append(string.Format(“IMDBLink: {0}”, IMDBLink));
24 return sb.ToString();
25 }
26 }
27 }
Here is the ASPX page which allows me to upload the XML file:
1 <%@ Page Language=”C#” AutoEventWireup=”true” CodeBehind=”LinqParseXml.aspx.cs” Inherits=”FrameworkTestBed.LinqParseXml” %>
2
3 <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
4
5 <html xmlns=”http://www.w3.org/1999/xhtml” >
6 <head runat=”server”>
7 <title>Linq Parse Xml</title>
8 </head>
9 <body>
10 <form id=”form1″ runat=”server”>
11 <div>
12 <p>
13 <b>XML file:</b>
14 <asp:FileUpload ID=”fileXml” runat=”server” />
15 <asp:Button ID=”btnUploadXmlFile” runat=”server” Text=”Upload Xml File” OnClick=”btnUploadXmlFile_Click” />
16 </p>
17 <p>
18 <asp:Label ID=”lblContent” runat=”server” />
19 </p>
20 </div>
21 </form>
22 </body>
23 </html>
Here is the code-behind using LINQ to parse the uploaded XML file:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.IO;
5 using System.Web;
6 using System.Web.UI;
7 using System.Web.UI.WebControls;
8 using System.Text;
9 using System.Xml.Linq;
10
11 namespace FrameworkTestBed
12 {
13 public partial class LinqParseXml : System.Web.UI.Page
14 {
15 protected void Page_Load(object sender, EventArgs e)
16 {
17 }
18
19 protected void btnUploadXmlFile_Click(object sender, EventArgs e)
20 {
21 if (fileXml.HasFile)
22 {
23 if (fileXml.PostedFile.ContentType == “text/xml”)
24 {
25 using (StreamReader reader = new StreamReader(fileXml.PostedFile.InputStream))
26 {
27 XDocument xdoc = XDocument.Parse(reader.ReadToEnd());
28
29 List<Member> members =
30 (
31 from item in xdoc.Descendants(“Member”)
32 select new Member
33 {
34 MemberId = Convert.ToInt32(item.Element(“MemberId”).Value),
35 Name = item.Element(“Name”).Value,
36 Character = item.Element(“Character”).Value,
37 IMDBLink = item.Element(“IMDBLink”).Value,
38 }
39 ).ToList<Member>();
40
41
42 StringBuilder sb = new StringBuilder();
43 foreach (var member in members)
44 {
45 sb.Append(string.Format(“{0}<br/>”, member));
46 }
47 lblContent.Text = sb.ToString();
48 }
49 }
50 }
51 }
52 }
53 }
The MemberId property is an integer type, we convert the element from string to integer with Convert.ToInt32().
Let’s upload member01.xml first:
Let’s upload member02.xml:
Crap, I got an exception – it’s because the missing XML element <IMDBLink>!
So I have to do something to prevent this from happening – check if the element exists before using its value. Let’s use the new features from C# 3.0 – Extension Methods:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Web;
5 using System.Xml.Linq;
6
7 namespace FrameworkTestBed
8 {
9 public static class XElementExtensions
10 {
11 public static T GetValue<T>(this XElement element, string name)
12 {
13 if (element.Element(name) == null)
14 {
15 return default(T);
16 }
17
18 try
19 {
20 return (T)Convert.ChangeType(element.Element(name).Value, typeof(T));
21 }
22 catch
23 {
24 return default(T);
25 }
26 }
27 }
28 }
I added one extension method on top of System.Xml.Linq.XElement: returns default generic type if the conversion fails.
Now let’s change the code-behind to use the new extension method:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.IO;
5 using System.Web;
6 using System.Web.UI;
7 using System.Web.UI.WebControls;
8 using System.Text;
9 using System.Xml.Linq;
10
11 namespace FrameworkTestBed
12 {
13 public partial class LinqParseXml : System.Web.UI.Page
14 {
15 protected void Page_Load(object sender, EventArgs e)
16 {
17 }
18
19 protected void btnUploadXmlFile_Click(object sender, EventArgs e)
20 {
21 if (fileXml.HasFile)
22 {
23 if (fileXml.PostedFile.ContentType == “text/xml”)
24 {
25 using (StreamReader reader = new StreamReader(fileXml.PostedFile.InputStream))
26 {
27 XDocument xdoc = XDocument.Parse(reader.ReadToEnd());
28
29 List<Member> members =
30 (
31 from item in xdoc.Descendants(“Member”)
32 select new Member
33 {
34 MemberId = item.GetValue<int>(“MemberId”),
35 Name = item.GetValue<string>(“Name”),
36 Character = item.GetValue<string>(“Character”),
37 IMDBLink = item.GetValue<string>(“IMDBLink”),
38 }
39 ).ToList<Member>();
40
41
42 StringBuilder sb = new StringBuilder();
43 foreach (var member in members)
44 {
45 sb.Append(string.Format(“{0}<br/>”, member));
46 }
47 lblContent.Text = sb.ToString();
48 }
49 }
50 }
51 }
52 }
53 }
Here is the result of parsing the member02.xml:
Now it works well with the extension method.
As I said, this is just a demonstration. We can use XML serialization/deserialization to achieve the same thing. Using LINQ to parse XML with the help of extension methods is just cool


