Reputation: 20334
As part of the base class for some extensive unit testing, I am writing a helper function which recursively compares the nodes of one XmlDocument object to another in C# (.NET). Some requirements of this:
xsi:schemaLocation
and xmlns:xsi
, though I would like to be able to pass in which ones are.InnerText
, but not both.While I'm scrapping something together: has anyone written such code and would it be possible to share it here?
On an aside, what would you call the first and second documents? I've been referring to them as "source" and "target", but it feels wrong since the source is what I want the target to look like, else I throw an exception.
Upvotes: 73
Views: 117102
Reputation: 1061
All above answers are helpful but I tried XMLUnit which look's easy to use Nuget package to check difference between two XML files, here is C# sample code
public static bool CheckXMLDifference(string xmlInput, string xmlOutput)
{
Diff myDiff = DiffBuilder.Compare(Input.FromString(xmlInput))
.WithTest(Input.FromString(xmlOutput))
.CheckForSimilar().CheckForIdentical()
.IgnoreComments()
.IgnoreWhitespace().NormalizeWhitespace().Build();
if(myDiff.Differences.Count() == 0)
{
// when there is no difference
// files are identical, return true;
return true;
}
else
{
//return false when there is 1 or more difference in file
return false;
}
}
If anyone want's to test it, I have also created online tool using it, you can take a look here
https://www.minify-beautify.com/online-xml-difference
Upvotes: 1
Reputation: 7710
Microsoft has an XML diff API that you can use.
Unofficial NuGet: https://www.nuget.org/packages/XMLDiffPatch.
Upvotes: 65
Reputation: 125
I solved this problem of xml comparison using XSLT 1.0 which can be used for comparing large xml files using an unordered tree comparison algorithm. https://github.com/sflynn1812/xslt-diff-turbo
Upvotes: 0
Reputation: 4735
For comparing two XML outputs in automated testing I found XNode.DeepEquals
.
Compares the values of two nodes, including the values of all descendant nodes.
Usage:
var xDoc1 = XDocument.Parse(xmlString1);
var xDoc2 = XDocument.Parse(xmlString2);
bool isSame = XNode.DeepEquals(xDoc1.Document, xDoc2.Document);
//Assert.IsTrue(isSame);
Reference: https://learn.microsoft.com/en-us/dotnet/api/system.xml.linq.xnode.deepequals?view=netcore-2.2
Upvotes: 8
Reputation: 81
This code doesn't satisfy all your requirements, but it's simple and I'm using for my unit tests. Attribute order doesn't matter, but element order does. Element inner text is not compared. I also ignored case when comparing attributes, but you can easily remove that.
public bool XMLCompare(XElement primary, XElement secondary)
{
if (primary.HasAttributes) {
if (primary.Attributes().Count() != secondary.Attributes().Count())
return false;
foreach (XAttribute attr in primary.Attributes()) {
if (secondary.Attribute(attr.Name.LocalName) == null)
return false;
if (attr.Value.ToLower() != secondary.Attribute(attr.Name.LocalName).Value.ToLower())
return false;
}
}
if (primary.HasElements) {
if (primary.Elements().Count() != secondary.Elements().Count())
return false;
for (var i = 0; i <= primary.Elements().Count() - 1; i++) {
if (XMLCompare(primary.Elements().Skip(i).Take(1).Single(), secondary.Elements().Skip(i).Take(1).Single()) == false)
return false;
}
}
return true;
}
Upvotes: 8
Reputation: 199
Based @Two Cents answer and using this link XMLSorting i have created my own XmlComparer
Compare XML program
private static bool compareXML(XmlNode node, XmlNode comparenode)
{
if (node.Value != comparenode.Value)
return false;
if (node.Attributes.Count>0)
{
foreach (XmlAttribute parentnodeattribute in node.Attributes)
{
string parentattributename = parentnodeattribute.Name;
string parentattributevalue = parentnodeattribute.Value;
if (parentattributevalue != comparenode.Attributes[parentattributename].Value)
{
return false;
}
}
}
if(node.HasChildNodes)
{
sortXML(comparenode);
if (node.ChildNodes.Count != comparenode.ChildNodes.Count)
return false;
for(int i=0; i<node.ChildNodes.Count;i++)
{
string name = node.ChildNodes[i].LocalName;
if (compareXML(node.ChildNodes[i], comparenode.ChildNodes[i]) == false)
return false;
}
}
return true;
}
Sort XML program
private static void sortXML(XmlNode documentElement)
{
int i = 1;
SortAttributes(documentElement.Attributes);
SortElements(documentElement);
foreach (XmlNode childNode in documentElement.ChildNodes)
{
sortXML(childNode);
}
}
private static void SortElements(XmlNode rootNode)
{
for(int j = 0; j < rootNode.ChildNodes.Count; j++) {
for (int i = 1; i < rootNode.ChildNodes.Count; i++)
{
if (String.Compare(rootNode.ChildNodes[i].Name, rootNode.ChildNodes[1 - 1].Name) < 0)
{
rootNode.InsertBefore(rootNode.ChildNodes[i], rootNode.ChildNodes[i - 1]);
}
}
}
// Console.WriteLine(j++);
}
private static void SortAttributes(XmlAttributeCollection attribCol)
{
if (attribCol == null)
return;
bool changed = true;
while (changed)
{
changed = false;
for (int i = 1; i < attribCol.Count; i++)
{
if (String.Compare(attribCol[i].Name, attribCol[i - 1].Name) < 0)
{
//Replace
attribCol.InsertBefore(attribCol[i], attribCol[i - 1]);
changed = true;
}
}
}
}
Upvotes: 0
Reputation: 9007
Not relevant for the OP since it currently ignores child order, but if you want a code only solution you can try XmlSpecificationCompare which I somewhat misguidedly developed.
Upvotes: 2
Reputation: 2166
https://github.com/CameronWills/FatAntelope Another alternative library to the Microsoft XML Diff API. It has a XML diffing algorithm to do an unordered comparison of two XML documents and produce an optimal matching.
It is a C# port of the X-Diff algorithm described here: http://pages.cs.wisc.edu/~yuanwang/xdiff.html
Disclaimer: I wrote it :)
Upvotes: 5
Reputation: 1668
I googled up a more complete list of solutions of this problem today, I am going to try one of them soon:
Upvotes: 9
Reputation: 6524
Comparing XML documents is complicated. Google for xmldiff (there's even a Microsoft solution) for some tools. I've solved this a couple of ways. I used XSLT to sort elements and attributes (because sometimes they would appear in a different order, and I didn't care about that), and filter out attributes I didn't want to compare, and then either used the XML::Diff or XML::SemanticDiff perl module, or pretty printed each document with every element and attribute on a separate line, and using Unix command line diff on the results.
Upvotes: 5
Reputation: 3020
try XMLUnit. This library is available for both Java and .Net
Upvotes: 7
Reputation: 31
I am using ExamXML for comparing XML files. You can try it. The authors, A7Soft, also provide API for comparing XML files
Upvotes: 3
Reputation: 1049
Another way to do this would be -
This won't give you the exact location of the difference, but if you just want to know if there is a difference, this is easy to do without any third party libraries.
Upvotes: 4