How to Compare Two XML Files in C#

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.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *