C#中的XML比较

14
我正在尝试使用C#代码比较两个Xml文件。 我希望忽略Xml语法差异(例如前缀名称)。 为此,我使用了微软的XML Diff and Patch C# API。 它适用于一些Xml,但我找不到一种方法来配置它以使其与以下两个Xml一起使用:

XML A:

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

XML B:

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

我的问题是:

  1. 我是否正确认为这两个XML在语义上是相等的(或同构的)?
  2. Microsoft的XML Diff和Patch API能否配置以支持它?
  3. 是否有其他C#工具可以执行此操作?
5个回答

10

以下程序演示了文档是同构的。如果你使用 Microsoft.XmlDiffPatch.XmlDiff 并配置 XmlDiffOptions.IgnoreNamespacesXmlDiffOptions.IgnorePrefixes,我认为你可以得到想要的结果。

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

1
忽略命名空间对我来说不太好 - 我认为具有不同命名空间的文档在语义上是不同的。 - Yaron Naveh
我明白,但是当执行比较时,XML Patch&Diff似乎会考虑命名空间,即使使用了IgnoreNamespaces。 我用两个文档<root xmlns="http://A" />和<root xmlns="http://B" />测试了这一点。 Diff&Patch认为它们是不同的。 不幸的是,我现在手头没有代码,所以无法100%确认。 - Ronald Wildenberg
我之前评论中的A和B是两个URL,但它们被转换为链接了... - Ronald Wildenberg
我得到了和你一样的结果。我想我之前犯了一个错误。继续调查... - Ronald Wildenberg
谢谢你提供的代码片段,这正是我所需要的。我刚刚添加了 if (!descendantA.HasElements) { var equalValues = valueA.Equals(valueB); } - LoBo
显示剩余3条评论

2

我知道你的重点不在单元测试上,但是XMLUnit可以比较两个XML文件,我认为它能够解决你的问题。也许你可以看看代码并找出你的解决方案。


实际上,我的重点是单元测试。 然而,在 .Net 中,XMLUnit 似乎也有类似的限制。它实际上可以用于上面的 Xml,但稍微有些变化就会出问题。 - Yaron Naveh

2
我在 XML 和 .NET Framework MSDN 论坛上得到了 Martin Honnen的一个答案。简而言之,他建议使用 XQuery 1.0 的 deep-equal 函数,并提供了一些 C# 实现。看起来可以工作。

1
也许从每个 XML 文件加载 XmlDocument 实例并比较 XML DOM 会是一个好主意?只要对每个实例进行正确的验证,这应该为您提供一个比较的公共基础,并应允许标准差异报告。甚至可能可以使用 delta 从一个更新到另一个。

这是一个选择 - 但我认为它是一个常见问题的常见解决方案,如果自己做可能会有些麻烦。 - Yaron Naveh

0

这些文档在语义上并不等同。第一个文档的顶层元素位于http://myNS命名空间中,而第二个文档的顶层元素位于默认命名空间中。

这两个文档的元素是等价的。但是这两个文档本身并不相同。

编辑:

xmls:ns='http://myNS'xmlns='http://myNS'之间存在着天壤之别,我似乎忽略了这一点。无论如何,这些文档在语义上是等价的,我只是弄错了。


那是不正确的。两个文档的顶级元素都在默认命名空间中。如果第一个文档的顶级元素只能在http://myNs命名空间中声明为<ns:root xmlns:ns="或" rel = "nofollow noreferrer">http://myNs">或<root xmlns="http://myNs">。 - Ronald Wildenberg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接