Comparing XML files is a common task in software development, often necessary for data synchronization, updates, and change tracking. This article demonstrates how to efficiently compare two XML files in C# using LINQ (Language Integrated Query), a powerful feature introduced in C# 3.0. We’ll cover creating a custom comparer and leveraging LINQ’s Except
method for identifying differences.
Understanding the Scenario
Consider a scenario where your application relies on a third-party web service providing data in XML format, such as a book catalog. You need to regularly update your local data with new books and synchronize existing information. This requires comparing your current XML file with the updated XML file from the web service.
Defining the Data Structure
First, let’s define a simple C# class to represent a book:
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;
}
}
Implementing a Custom Comparer
To compare book objects based on a specific criterion (e.g., BookID
), we need a custom comparer that implements the IEqualityComparer<Book>
interface:
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();
}
}
This comparer determines that two Book
objects are equal if their BookID
values are the same.
Loading and Comparing XML Data
The core logic for comparing XML files involves loading them into collections of Book
objects and using LINQ’s Except
method along with our custom comparer:
// Load XML files into IEnumerable<Book> collections
IEnumerable<Book> bookA = LoadBooksFromXML("Books_A.xml");
IEnumerable<Book> bookB = LoadBooksFromXML("Books_B.xml");
// Instantiate the custom comparer
BookComparer oComparer = new BookComparer();
// Use Except to find books in bookA not present in bookB
var comparerList = bookA.Except(bookB, oComparer).ToList();
//Combine the results and save to a new XML file
List<Book> result = new List<Book>();
result.AddRange(comparerList);
result.AddRange(bookB);
result = result.OrderBy(book => book.BookID).ToList();
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"));
//Helper function to load 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;
}
This code snippet efficiently identifies differences between two XML files based on the specified criteria. The Except
method, combined with the custom comparer, ensures accurate comparison, enabling you to synchronize and update your data effectively. The resulting XML file (“result.xml”) contains the merged and updated book data.