Compare xml files using C# LINQ


In this article you will learn how to compare two xml files using C# LINQ (Language Integrated Query one of the great features  in C# 3.0 release) .Imagine a scenario where you are consuming a third party web service for online book selling site. Every day you may need to update your site if any new book is launched and also you want to sync with your existing information. I am going to create a simple class called Book with three properties.  (You can download the  article source code from the bottom of the page.)

public class Book
{
 public Book()
 {

 }
 public int BookID { get; set; }
 public String Name { get; set; }
 public double Price { get; set; }
 public Book(int bookId, string name, double price)
 {
 this.BookID = bookId;
 this.Name = name;
 this.Price = price;
 }

}

The next step is to create custom comparer class which implements IEqualityComparer. The comparer class  returns true if both bookId’s  are equal.

public class BookComparer : IEqualityComparer<Book>
{
 public bool Equals(Book x, Book y)
 {
 return (x.BookID == y.BookID);
 }

 public int GetHashCode(Book book)
 {
 return book.BookID.GetHashCode();
 }
}

Sample XML files

Book_A.xml

<?xml version="1.0" encoding="utf-8" ?>
<Books>
 <Book bookId="100" name="Asp.Net" price = "230" />
 <Book bookId="101" name="C#" price = "200" />
 <Book bookId="102" name="Silverlight" price = "300" />
 <Book bookId="103" name="MFC Book" price = "300" />
</Books>

Book_B.xml

<?xml version="1.0" encoding="utf-8" ?>
<Books>
 <Book bookId="100" name="Asp.Net" price = "230" />
 <Book bookId="101" name="C#" price = "200" />
 <Book bookId="102" name="Silverlight" price = "300" />
 <Book bookId="104" name="WPF" price = "200" />
 <Book bookId="105" name="WCF" price = "200" />
</Books>

Result.XML

<?xml version="1.0" encoding="utf-8"?>
<Books>
 <Book bookId="100" name="Asp.Net" price="230" />
 <Book bookId="101" name="C#" price="200" />
 <Book bookId="102" name="Silverlight" price="300" />
 <Book bookId="103" name="MFC Book" price="300" />
 <Book bookId="104" name="WPF" price="200" />
 <Book bookId="105" name="WCF" price="200" />
</Books>

Default.aspx.cs

protected void Page_Load(object sender, EventArgs e)
 {
 IEnumerable<Book> bookA = LoadXML("Books_A.xml");
 IEnumerable<Book> bookB = LoadXML("Books_B.xml");
 BookComparer oComparer = new BookComparer();
 var comparerList = bookA.Except(bookB, oComparer).ToList();
 List<Book> result = new List<Book>();
 result.AddRange(comparerList);
 result.AddRange(bookB);
 result = (from book in result
 orderby book.BookID ascending
 select book).ToList<Book>();

 XElement xElement = new XElement("Books",
 from book in result
 select new XElement("Book",
 new XAttribute("bookId", book.BookID.ToString()),
 new XAttribute("name", book.Name),
 new XAttribute("price", book.Price)
 )
 );
 xElement.Save(Server.MapPath("~/XML/result.xml"));
 }

 IEnumerable<Book> LoadBooksFromXML(string fileName)
 {
 XElement xml = XElement.Load(Server.MapPath("~/XML/" + fileName));
 var query = (from book in xml.Descendants("Book")
 orderby (int)book.Attribute("bookId") ascending
 select new Book(
 (int)book.Attribute("bookId"),
 (string)book.Attribute("name") != null ? (string)book.Attribute("name") : string.Empty,
 (double)book.Attribute("price"))
 );
 return query;
 }

Code Explanation

IEnumerable<Book> bookA = LoadXML(“Books_A.xml”);

LoadXML method load xml file and return a collection of Book class

BookComparer oComparer = new BookComparer(); //The BookComparer class instantiate a new object

var comparerList = bookA.Except(bookB, oComparer).ToList();

The above statement will compare the items in Books_A.xml  with Books_B.xml and return a collection of items which is not found in Book_B.xml

Based on the above XML files the return list would be some thing like below

<Book bookId=”103″ name=”MFC Book” price = “300” />

Finally we need to merge the items in to a new list and save as result.xml file.

Create a new List for hold the result list

List<Book> result = new List<Book>();
result.AddRange(comparerList);  //
result list
result.AddRange(bookB); //
book_B.xml collection.

//sort by book id ascending

result = (from book in result
orderby book.BookID ascending
select book).ToList<Book>();

//Save as new xml file.

XElement xElement = new XElement(“Books”,
from book in result
select new XElement(“Book”,
new XAttribute(“bookId”, book.BookID.ToString()),
new XAttribute(“name”, book.Name),
new XAttribute(“price”, book.Price)
)
);
xElement.Save(Server.MapPath(“~/XML/result.xml”));

You can download the entire article from here or copy paste this URL

http://www.4shared.com/file/232888750/82ac9ddf/XMLComparer.html

Hope this help and If you have any comments, please feel free to write your feedback.

Thanks
Deepu