C# 比较 XML 文件是否相等的最佳方法是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/299553/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 22:14:29  来源:igfitidea点击:

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

c#.netxmlunit-testingcomparison

提问by Scott Lawrence

I'm using .NET 2.0, and a recent code change has invalidated my previous Assert.AreEqual call (which compared two strings of XML). Only one element of the XML is actually different in the new codebase, so my hope is that a comparison of all the other elements will give me the result I want. The comparison needs to be done programmatically, since it's part of a unit test.

我正在使用 .NET 2.0,最近的代码更改使我之前的 Assert.AreEqual 调用(它比较了两个 XML 字符串)无效。在新的代码库中,实际上只有 XML 的一个元素是不同的,所以我希望所有其他元素的比较会给我想要的结果。比较需要以编程方式完成,因为它是单元测试的一部分。

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

起初,我正在考虑使用几个 XmlDocument 实例。但后来我发现了这个:http: //drowningintechnicaldebt.com/blogs/scottroycraft/archive/2007/05/06/comparing-xml-files.aspx

It looks like it might work, but I was interested in Stack Overflow feedback in case there's a better way.

看起来它可能有效,但我对 Stack Overflow 的反馈很感兴趣,以防有更好的方法。

I'd like to avoid adding another dependency for this if at all possible.

如果可能的话,我想避免为此添加另一个依赖项。

Similar questions

类似问题

采纳答案by Filini

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

这实际上取决于您要检查的“差异”。

Right now, we're using Microsoft XmlDiff: http://msdn.microsoft.com/en-us/library/aa302294.aspx

现在,我们正在使用 Microsoft XmlDiff:http: //msdn.microsoft.com/en-us/library/aa302294.aspx

回答by Filini

Doing a simple string compare on a xmlstring not always work. Why ?

对字符串进行简单的字符串比较xml并不总是有效。为什么 ?

for example both :

例如两者:

<MyElement></MyElmennt>and <MyElment/>are equal from an xmlstandpoint ..

<MyElement></MyElmennt>并且<MyElment/>从一个xml角度来看是平等的..

There are algorithms for converting making an xmlalways look the same, they are called canonicalization algorithms. .Nethas support for canonicalization.

有一些算法用于转换使xml看起来总是相同的,它们被称为规范化算法。.Net支持规范化。

回答by jlew

You might find it's less fragile to parse the XML into an XmlDocument and base your Assert calls on XPath Query. Here are some helper assertion methods that I use frequently. Each one takes a XPathNavigator, which you can obtain by calling CreateNavigator() on the XmlDocument or on any node retrieved from the document. An example of usage would be:

您可能会发现将 XML 解析为 XmlDocument 并将您的 Assert 调用建立在 XPath Query 上没有那么脆弱。以下是我经常使用的一些辅助断言方法。每个都有一个 XPathNavigator,您可以通过在 XmlDocument 或从文档中检索到的任何节点上调用 CreateNavigator() 来获取它。一个使用示例是:

     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 ) );
    }

回答by Tim Jarvis

Because of the contents of an XML file can have different formatting and still be considered the same (from a DOM point of view) when you are testing the equality you need to determine what the measure of that equality is, for example is formatting ignored? does meta-data get ignored etc is positioning important, lots of edge cases.

由于 XML 文件的内容可以具有不同的格式,并且在测试相等性时仍然被认为是相同的(从 DOM 的角度来看),因此您需要确定该相等性的度量是什么,例如是否忽略了格式?元数据是否被忽略等定位很重要,很多边缘情况。

Generally you would 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 inbuilt framework lists as the equality test implementation as well. Plus of course you can have as many as you need to measure equality differently as your requirements require.

通常,您会创建一个定义相等规则的类并将其用于比较,如果您的比较类实现了IEqualityComparer and/or IEqualityComparer<T>接口,那么您的类也可以在一堆内置框架列表中用作相等测试实现。另外,当然,您可以根据需要根据需要以不同的方式衡量相等性。

i.e

IE

IEnumerable<T>.Contains
IEnumerable<T>.Equals
The constructior of a Dictionary etc etc

回答by Scott Lawrence

I ended up getting the result I wanted 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 on the instance of XmlDocument this way:

在调用该方法之前,我以这种方式在 XmlDocument 的实例上创建了一个导航器:

XPathNavigator nav = xdoc.CreateNavigator();

Next, I create an instance of XPathExpression, like so:

接下来,我创建一个 XPathExpression 实例,如下所示:

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

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

我在使用表达式创建迭代器后调用该方法:

XPathNodeIterator iterator = nav.Select(expression);

I'm still figuring out how to optimize it further, but it does the trick for now.

我仍在弄清楚如何进一步优化它,但它现在可以解决问题。

回答by Johan Larsson

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

我写了一个带有序列化断言的小型库,source

Sample:

样本:

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

NuGet

NuGet

回答by DLeh

I made a method to create simple XML paths.

我做了一个方法来创建简单的 XML 路径。

static XElement MakeFromXPath(string xpath)
{
    XElement root = null;
    XElement parent = null;
    var splits = xpath.Split('/'); //split xpath into parts
    foreach (var split in splits)
    {
        var el = new XElement(split);
        if (parent != null)
            parent.Add(el);
        else
            root = el; //first element created, set as root
        parent = el;
    }
    return root;
}

Sample usage:

示例用法:

var element = MakeFromXPath("My/Path/To/Element")'

var element = MakeFromXPath("My/Path/To/Element")'

elementwill contain the value:

element将包含以下值:

<My>
  <Path>
    <To>
      <Element></Element>
    </To>
  </Path>
</My>