What is the best way to compare XML files for equality?

I am using .NET 2.0, and a recent change to the code invalidates my previous call to Assert.AreEqual (which compared two lines of XML). Only one XML element is actually different from the new code base, so I hope that comparing all the other elements will give me the result that I want. The comparison should be done programmatically, as it is part of the unit test.

At first, I considered using multiple instances of XmlDocument. But then I found this: http://drowningintechnicaldebt.com/blogs/scottroycraft/archive/2007/05/06/comparing-xml-files.aspx

It seems like this might work, but I was interested in the stack overflow feedback if there is a better way.

I would like to avoid adding another dependency for this, if at all possible.

Related questions

  • Are there any XML statements for NUnit?
  • How would you compare two XML documents?
+12
comparison c # xml unit-testing
Nov 18 '08 at 17:50
source share
6 answers

It really depends on what you want to check for as "differences."

We are now using Microsoft XmlDiff: http://msdn.microsoft.com/en-us/library/aa302294.aspx

+10
Nov 18 '08 at 17:56
source share

You may find it less fragile to parse XML in an XmlDocument and create your Assert calls in XPath Query. Here are some helper assertion methods that I often use. Each of them accepts XPathNavigator, which you can get by calling CreateNavigator () in an XmlDocument or on any node extracted from a document. Usage example:

XmlDocument doc = new XmlDocument( "Testdoc.xml" ); XPathNavigator nav = doc.CreateNavigator(); AssertNodeValue( nav, "/root/foo", "foo_val" ); AssertNodeCount( nav, "/root/bar", 6 ) private static void AssertNodeValue(XPathNavigator nav, string xpath, string expected_val) { XPathNavigator node = nav.SelectSingleNode(xpath, nav); Assert.IsNotNull(node, "Node '{0}' not found", xpath); Assert.AreEqual( expected_val, node.Value ); } private static void AssertNodeExists(XPathNavigator nav, string xpath) { XPathNavigator node = nav.SelectSingleNode(xpath, nav); Assert.IsNotNull(node, "Node '{0}' not found", xpath); } private static void AssertNodeDoesNotExist(XPathNavigator nav, string xpath) { XPathNavigator node = nav.SelectSingleNode(xpath, nav); Assert.IsNull(node, "Node '{0}' found when it should not exist", xpath); } private static void AssertNodeCount(XPathNavigator nav, string xpath, int count) { XPathNodeIterator nodes = nav.Select( xpath, nav ); Assert.That( nodes.Count, Is.EqualTo( count ) ); } 
+3
Nov 18 '08 at 18:46
source share

Performing simple string comparisons in an xml string does not always work. Why?

for example, both:

<MyElement></MyElmennt> and <MyElment/> are equal in terms of xml .

There are conversion algorithms in which xml always look the same, they are called canonicalization algorithms. .Net supports canonicalization.

+1
Nov 18 '08 at 18:08
source share

I wrote a small library with claims for serialization, source .

Example:

 [Test] public void Foo() { ... XmlAssert.Equal(expected, actual, XmlAssertOptions.IgnoreDeclaration | XmlAssertOptions.IgnoreNamespaces); } 

Nuget

+1
Apr 29 '16 at 6:45
source share

Due to the fact that the contents of the XML file can have different formatting and are still considered the same (from the DOM point of view), when you check for equality, you need to determine what measure of this equality is, for example, formatting is ignored? meta data is ignored, etc. positioning important, many extreme cases.

Typically, you should create a class that defines your equality rules and use it for your comparisons, and if your comparison class implements the IEqualityComparer and/or IEqualityComparer<T> interfaces, then your class can be used in a bunch of built-in frame lists as an equality test also. Plus, of course, you can have as much as you need to measure equality in different ways, as your requirements require.

ie

 IEnumerable<T>.Contains IEnumerable<T>.Equals The constructior of a Dictionary etc etc 
0
Nov 18 '08 at 21:43
source share

In the end, I got the result I need, with the following code:

 private static void ValidateResult(string validationXml, XPathNodeIterator iterator, params string[] excludedElements) { while (iterator.MoveNext()) { if (!((IList<string>)excludedElements).Contains(iterator.Current.Name)) { Assert.IsTrue(validationXml.Contains(iterator.Current.Value), "{0} is not the right value for {1}.", iterator.Current.Value, iterator.Current.Name); } } } 

Before calling the method, I create a navigator in the XmlDocument instance as follows:

 XPathNavigator nav = xdoc.CreateNavigator(); 

Next, I create an instance of XPathExpression, for example:

 XPathExpression expression = XPathExpression.Compile("/blah/*"); 

I call the method after creating an iterator with an expression:

 XPathNodeIterator iterator = nav.Select(expression); 

I am still figuring out how to optimize it further, but now this is a trick.

0
Nov 19 '08 at 23:08
source share



All Articles