比较 XmlDocument 是否相等(内容明智)

问题描述 投票:0回答:6

如果我要比较一个XMlDocument的内容,是不是就这样?

XmlDocument doc1 = GetDoc1();
XmlDocument doc2 = GetDoc2();

if(doc1 == doc2)
{

}

我不是在检查它们是否都是相同的对象引用,而是在检查 xml 的内容是否相同。

c# xml xmldocument equality
6个回答
41
投票

在 XLinq API 上尝试 DeepEquals 方法。

XDocument doc1 = GetDoc1(); 
XDocument doc2 = GetDoc2(); 
 
if(XNode.DeepEquals(doc1, doc2)) 
{ 
 
} 

另见LINQ to XML 树的相等语义


12
投票

没有。 XmlDocument 不会覆盖

Equals()
方法 的行为,因此,它实际上只是执行引用相等 - 在您的示例中这将失败,除非文档实际上是相同的对象实例。

如果你想比较文档的内容(属性、元素、评论、PI 等),你必须自己实现该逻辑。 警告:这不是微不足道的。

根据您的具体情况,您可以从文档中删除所有非必要的空格(这本身可能很棘手),然后他们比较生成的 xml 文本。这并不完美——对于语义相同但在名称空间的使用和声明方式、某些值是否被转义、元素顺序等方面有所不同的文档,它会失败。正如我之前所说,XML 比较并非微不足道。

您还需要清楚地定义两个 XML 文档“相同”的含义。 元素或属性的顺序重要吗?大小写(在文本节点中)重要吗?您应该忽略多余的 CDATA 部分吗?处理指令算吗?完全限定与部分限定的名称空间怎么样?

在任何通用实现中,您可能希望将两个文档都转换为某种规范形式(无论是 XML 还是其他表示形式),然后比较规范化的内容。

执行 XML 差异的工具已经存在,例如 Microsoft XML Diff/Patch 您可以利用它来识别两个文档之间的差异。据我所知,该工具不是以源代码形式分发的……所以要在嵌入式应用程序中使用它,您需要编写该过程的脚本(如果您打算使用它,您应该首先验证许可条款是否允许它的使用和再分发).

编辑: 如果您使用的是 .NET 3.5 SP1,请查看@Max Toro 的回答,显然 XLinq 中有一个选项可能会有帮助。很高兴知道它存在。


11
投票

一个简单的方法可能是比较

OuterXml
.

var a = new XmlDocument();
var b = new XmlDocument();

a.LoadXml("<root  foo='bar'  />");
b.LoadXml("<root foo='bar'/>");

Debug.Assert(a.OuterXml == b.OuterXml);

0
投票

L布什金是对的,这不是小事。由于 XML 是字符串数据,您可以从技术上对内容执行散列并进行比较,但这会受到空格等因素的影响。

您可以在两个文档之间执行结构化差异(也称为“XML 差异图”)并比较结果。例如,这就是 .NET 数据集跟踪变化的方式。

除此之外,您必须遍历 DOM 并将元素、属性和值相互比较。如果涉及模式,那么您还必须考虑位置等。


0
投票

通常你想比较不同顺序的 XML 字符串。这可以用这段代码轻松完成

class Testing
{
    [Test]
    public void Test()
    {
        Assert.AreEqual(
            "<root><a></a><b></b></root>".SortXml()
            , "<root><b></b><a></a></root>".SortXml());
    }
}

public static class XmlCompareExtension
{
    public static string SortXml(this string @this)
    {
        var xdoc = XDocument.Parse(@this);

        SortXml(xdoc);

        return xdoc.ToString();
    }

    private static void SortXml(XContainer parent)
    {
        var elements = parent.Elements()
            .OrderBy(e => e.Name.LocalName)
            .ToArray();

        Array.ForEach(elements, e => e.Remove());

        foreach (var element in elements)
        {
            parent.Add(element);
            SortXml(element);
        }
    }
}

0
投票

我知道这个问题有多老,但我必须通过多个来源才能找到我正在寻找的答案。以下是使用 XNode.DeepEquals 但也忽略了属性顺序。在第一次提出这个问题 13 年后,我必须做大量的工作才能得出这个答案,我想其他人可能会觉得这个答案有帮助。

使用 NUnit 作为我的测试套件,您可以传入 2 个 XmlDocument 或一个 XmlDocument 和字符串。这会将 XmlDocuments 转换为 XDocuments,对每个节点的属性进行排序,然后执行 XNode.DeepEquals()。

Assert.That(XmlHelperService.XMLCompare(xmlDoc, expectedStr), Is.EqualTo(true));
Assert.That(XmlHelperService.XMLCompare(xmlDoc, expectedXmlDoc), Is.EqualTo(true));

代码

public class XmlHelperService
{
    public static bool XMLCompare(XmlDocument primary, string secondaryStr)
    {
        XmlDocument secondary = new XmlDocument();
        secondary.LoadXml(secondaryStr);

        return XMLCompare(primary, secondary);
    }

    public static bool XMLCompare(XmlDocument primary, XmlDocument secondary)
    {
        return XNode.DeepEquals(NormalizeXElement(primary.ToXDocument().Root), NormalizeXElement(secondary.ToXDocument().Root));
    }

    private static XElement NormalizeXElement(XElement element)
    {
        return new XElement(element.Name,
            element.Attributes().OrderBy(x => x.Name.ToString()),
            element.Nodes().Select(n =>
            {
                XElement e = n as XElement;
                if (e != null)
                    return NormalizeXElement(e);
                return n;
            })
        );
    }
}

public static class DocumentExtensions
{
    public static XDocument ToXDocument(this XmlDocument xmlDocument)
    {
        using (var nodeReader = new XmlNodeReader(xmlDocument))
        {
            nodeReader.MoveToContent();
            return XDocument.Load(nodeReader);
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.