13

I'm trying to compare two Xml files using C# code. I want to ignore Xml syntax differences (i.e. prefix names). For that I am using Microsoft's XML Diff and Patch C# API. It works for some Xml's but I couldn't find a way to configure it to work with the following two Xml's:

XML A:

<root xmlns:ns="http://myNs">
  <ns:child>1</ns:child>
</root>

XML B:

<root>
  <child xmlns="http://myNs">1</child>
</root>

My questions are:

  1. Am I right that these two xml's are semantically equal (or isomorphic)?
  2. Can Microsoft's XML Diff and Patch API be configured to support it?
  3. Are there any other C# utilities to to this?
TStamper
  • 30,098
  • 10
  • 66
  • 73
Yaron Naveh
  • 23,560
  • 32
  • 103
  • 158

5 Answers5

10

The documents are isomorphic as can be shown by the program below. I think if you use XmlDiffOptions.IgnoreNamespaces and XmlDiffOptions.IgnorePrefixes to configure Microsoft.XmlDiffPatch.XmlDiff, you get the result you want.

using System.Linq;
using System.Xml.Linq;
namespace SO_794331
{
    class Program
    {
        static void Main(string[] args)
        {
            var docA = XDocument.Parse(
                @"<root xmlns:ns=""http://myNs""><ns:child>1</ns:child></root>");
            var docB = XDocument.Parse(
                @"<root><child xmlns=""http://myNs"">1</child></root>");

            var rootNameA = docA.Root.Name;
            var rootNameB = docB.Root.Name;
            var equalRootNames = rootNameB.Equals(rootNameA);

            var descendantsA = docA.Root.Descendants();
            var descendantsB = docB.Root.Descendants();
            for (int i = 0; i < descendantsA.Count(); i++)
            {
                var descendantA = descendantsA.ElementAt(i);
                var descendantB = descendantsB.ElementAt(i);
                var equalChildNames = descendantA.Name.Equals(descendantB.Name);

                var valueA = descendantA.Value;
                var valueB = descendantB.Value;
                var equalValues = valueA.Equals(valueB);
            }
        }
    }
}
Eddie
  • 53,828
  • 22
  • 125
  • 145
Ronald Wildenberg
  • 31,634
  • 14
  • 90
  • 133
  • 1
    IgnoreNamespaces is not good for me - I consider documents with different namespaces to be different semantically. – Yaron Naveh Apr 28 '09 at 12:03
  • I understand, but it seems that XML Patch&Diff does takes namespaces into account when comparing, even when IgnoreNamespaces is used. I tested this with two documents and . Diff&Patch thinks they're different. Unfortunately I haven't got the code with me now, so I can't confirm this 100%. – Ronald Wildenberg Apr 28 '09 at 12:15
  • A and B in my previous comment were meant to be two urls but they were converted to links... – Ronald Wildenberg Apr 28 '09 at 12:16
  • When I try it I get that they're equal – Yaron Naveh Apr 30 '09 at 10:08
  • I get the same result you get. I think I made a mistake before. Continuing the investigation... – Ronald Wildenberg May 01 '09 at 08:17
  • I posted an issue on Microsoft Connect: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=437072. I do not see any other explanation than that it's a bug. – Ronald Wildenberg May 01 '09 at 08:47
  • They have escalated the issue, so it seems to be a real bug: 'We are escalating this issue to the appropriate group within the Visual Studio Product Team for triage and resolution. These specialized experts will follow-up with your issue' – Ronald Wildenberg May 05 '09 at 11:36
  • Thanks for the code snippet, it is all I needed. I have just added `if (!descendantA.HasElements) { var equalValues = valueA.Equals(valueB); }` – LoBo Jan 24 '15 at 14:27
2

I know that you're focus isn't on unit tests, but XMLUnit can compare two XML files and I think it's able to solve your example. Maybe you could look at the code ahd figure out your solution.

rguerreiro
  • 2,673
  • 3
  • 22
  • 23
  • Actually my focus is on unit tests. However XMLUnit also seems to have similar limitations in .Net. It actually worked for the Xml's above but a slight variation broke it. – Yaron Naveh Apr 28 '09 at 12:01
2

I've got an answer by Martin Honnen in XML and the .NET Framework MSDN Forum. In short he suggests to use XQuery 1.0's deep-equal function and supplies some C# implementations. Seems to work.

Yaron Naveh
  • 23,560
  • 32
  • 103
  • 158
1

It might be an idea to load XmlDocument instances from each xml file, and compare the XML DOM instead? Providing the correct validation is done on each, that should give you a common ground for a comparison, and should allow standard difference reporting. Possibly even the ability to update one from the other with the delta.

Neil Barnwell
  • 41,080
  • 29
  • 148
  • 220
  • It's an option - but it's doing by myself something which I believe to be a common problem with a common solution. – Yaron Naveh Apr 28 '09 at 12:02
0

Those documents aren't semantically equivalent. The top-level element of the first is in the http://myNS namespace, while the top-level element of the second is in the default namespace.

The child elements of the two documents are equivalent. But the documents themselves aren't.

Edit:

There's a world of difference between xmls:ns='http://myNS' and xmlns='http://myNS', which I appear to have overlooked. Anyway, those documents are semantically equivalent and I'm just mistaken.

Robert Rossney
  • 94,622
  • 24
  • 146
  • 218
  • That's incorrect. The top-level elements of both documents are in the default namespace. The top-level element of the first document can only be in the http://myNs namespace if it is declared either as or – Ronald Wildenberg Apr 27 '09 at 19:16