Archive

Archive for the ‘LINQ’ Category

Using LINQ to parse XML

April 14, 2010 Leave a comment

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”&gt;

4

5 <html xmlns=”http://www.w3.org/1999/xhtml&#8221; >

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 :)

Categories: ASP.NET, C#, LINQ, XML Tags: , ,
Follow

Get every new post delivered to your Inbox.