简体   繁体   English

您将如何比较两个 XML 文档?

[英]How would you compare two XML Documents?

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).作为一些广泛单元测试的基类的一部分,我正在编写一个辅助函数,它递归地比较一个 XmlDocument 对象的节点与 C# (.NET) 中的另一个。 Some requirements of this:对此的一些要求:

  • The first document is the source , eg what I want the XML document to look like.第一个文档是文件,例如我希望 XML 文档的样子。 Thus the second is the one I want to find differences in and it must not contain extra nodes not in the first document.因此,第二个是我想要找到差异的那个,它不能包含第一个文档中没有的额外节点。
  • Must throw an exception when too many significant differences are found, and it should be easily understood by a human glancing at the description.当发现太多显着差异时必须抛出异常,并且应该很容易被人类看一眼描述理解。
  • Child element order is important, attributes can be in any order.子元素顺序很重要,属性可以是任何顺序。
  • Some attributes are ignorable;有些属性是可以忽略的; specifically xsi:schemaLocation and xmlns:xsi , though I would like to be able to pass in which ones are.特别是xsi:schemaLocationxmlns:xsi ,尽管我希望能够传入哪些是。
  • Prefixes for namespaces must match in both attributes and elements.命名空间的前缀必须在属性和元素中匹配。
  • Whitespace between elements is irrelevant.元素之间的空白是无关紧要的。
  • Elements will either have child elements or InnerText , but not both.元素要么有子元素InnerText ,但不能同时使用。

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.我一直将它们称为“源”和“目标”,但感觉不对,因为是我希望目标的样子,否则我会抛出异常。

Microsoft has an XML diff API that you can use. Microsoft 有一个您可以使用的XML 差异 API

Unofficial NuGet: https://www.nuget.org/packages/XMLDiffPatch .非官方 NuGet: https : //www.nuget.org/packages/XMLDiffPatch

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

Comparing XML documents is complicated.比较 XML 文档很复杂。 Google for xmldiff (there's even a Microsoft solution) for some tools.谷歌搜索 xmldiff(甚至还有微软的解决方案)来获取一些工具。 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.我使用 XSLT 对元素和属性进行排序(因为有时它们会以不同的顺序出现,而我并不关心这一点),并过滤掉我不想比较的属性,然后使用XML::DiffXML::SemanticDiff perl 模块,或者在单独的行上使用每个元素和属性漂亮地打印每个文档,并在结果上使用 Unix 命令行差异。

try XMLUnit .试试XMLUnit This library is available for both Java and .Net该库可用于 Java 和 .Net

For comparing two XML outputs in automated testing I found XNode.DeepEquals .为了在自动化测试中比较两个 XML 输出,我发现了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://docs.microsoft.com/en-us/dotnet/api/system.xml.linq.xnode.deepequals?view=netcore-2.2参考: https : //docs.microsoft.com/en-us/dotnet/api/system.xml.linq.xnode.deepequals?view=netcore-2.2

I am using ExamXML for comparing XML files.我正在使用ExamXML来比较 XML 文件。 You can try it.你可以试试看。 The authors, A7Soft, also provide API for comparing XML files作者 A7Soft 还提供了用于比较 XML 文件的 API

https://github.com/CameronWills/FatAntelope Another alternative library to the Microsoft XML Diff API. https://github.com/CameronWills/FatAntelope Microsoft XML Diff API 的另一个替代库。 It has a XML diffing algorithm to do an unordered comparison of two XML documents and produce an optimal matching.它有一个 XML diffing 算法来对两个 XML 文档进行无序比较并产生最佳匹配。

It is a C# port of the X-Diff algorithm described here: http://pages.cs.wisc.edu/~yuanwang/xdiff.html它是此处描述的 X-Diff 算法的 C# 端口: http : //pages.cs.wisc.edu/~yuanwang/xdiff.html

Disclaimer : I wrote it :)免责声明:我写的:)

与 OP 无关,因为它目前忽略子订单,但如果您想要一个纯代码解决方案,您可以尝试XmlSpecificationCompare ,我有点误导性地开发了它。

Another way to do this would be -另一种方法是 -

  1. Get the contents of both files into two different strings.将两个文件的内容放入两个不同的字符串中。
  2. Transform the strings using an XSLT (which will just copy everything over to two new strings).使用 XSLT 转换字符串(它只会将所有内容复制到两个新字符串)。 This will ensure that all spaces outside the elements are removed.这将确保删除元素之外的所有空格。 This will result it two new strings.这将产生两个新字符串。
  3. Now, just compare the two strings with each other.现在,只需将两个字符串相互比较即可。

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.这不会为您提供差异的确切位置,但如果您只想知道是否存在差异,则无需任何第三方库即可轻松完成。

Based @Two Cents answer and using this link XMLSorting i have created my own XmlComparer基于@Two Cents 回答并使用此链接XMLSorting我创建了自己的 XmlComparer

Compare XML program比较 XML 程序

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排序 XML 程序

 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;

                }
            }
        }
    }

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.我使用 XSLT 1.0 解决了这个 xml 比较问题,它可用于使用无序树比较算法比较大型 xml 文件。 https://github.com/sflynn1812/xslt-diff-turbo https://github.com/sflynn1812/xslt-diff-turbo

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以上所有答案都有帮助,但我尝试了XMLUnit ,它看起来很容易使用 Nuget 包来检查两个 XML 文件之间的差异,这里是 C# 示例代码

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 https://www.minify-beautify.com/online-xml-difference

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM