在 C# (.net 2.0) 中比较大型 XML 文件

本文关键字:比较 大型 XML 文件 net | 更新日期: 2023-09-27 18:36:33

我不得不使用 .Net 2.0,所以 LINQ xml 不可用,尽管我很感兴趣它会如何比较......

我必须编写一个内部程序来下载、提取和比较一些大型 XML 文件(每个大约 10 megs),这些文件本质上是构建配置。我首先尝试使用库,例如Microsoft的 XML diff/patch,但比较文件需要 2-3 分钟,即使忽略空格、命名空间等(我一次测试了一个忽略,试图找出最快的)。我试图实现我自己的想法 - 来自 XmlDocument 对象的节点列表,根直系后代(顺便说一下,45000 个子项)的键字典,指向整数以指示节点在 XML 文档中的位置...... 所有运行至少需要 2 分钟。

我的最终实现在 1-2 秒内完成 - 我用几行上下文对 diff 进行了系统进程调用,并将这些结果保存下来显示(谢天谢地,我们的开发机器包括 cygwin)。

我不禁认为有一种更好的、特定于 XML 的方法可以做到这一点,它与纯文本差异一样快 - 特别是因为我真正感兴趣的只是 Name 元素,它是每个直系后代的子元素,并且可以丢弃 4/5 的文件用于我的目的(我们只需要知道包含哪些文件, 不涉及语言或版本的任何其他内容)

所以,尽管XML很流行,但我敢肯定有人不得不做类似的事情。比较这些大型 XML 的快速有效方法是什么?(最好是开源或免费)

编辑:节点示例 - 我只需要找到缺少的名称元素(也有超过 45k 个节点)

<file>
     <name>SomeFile</name>
     <version>10.234</version>
     <countries>CA,US</countries>
     <languages>EN</languages>
     <types>blah blah</types>
     <internal>N</internal>
</file>

在 C# (.net 2.0) 中比较大型 XML 文件

XmlDocument source = new XmlDocument();
source.Load("source.xml");
Dictionary<string, XmlNode> files = new Dictionary<string, XmlNode>();
foreach(XmlNode file in source.SelectNodes("//file"))
    files.Add(file.SelectSingleNode("./name").InnerText, file);
XmlDocument source2 = new XmlDocument();
source2.Load("source2.xml");
XmlNode value;
foreach(XmlNode file in source2.SelectNodes("//file"))
    if (files.TryGetValue(file.SelectSingleNode("./name").InnerText, out value))
      // This file is both in source and source2.
    else
      // This file is only in source2.

我不确定你到底想要什么,我希望这个例子能帮助你完成你的追求。

比较XML可以通过多种方式完成。不过,您对细节不是很具体。确实是文件很大,您只需要 4/5 的信息。

那么,算法如下:

  • 规范化文档并将其缩减为重要信息。
  • 保存结果。
  • 比较结果。

实现

  • 使用 XmlReader API (非常高效)生成信息的纯文本表示形式。为什么选择纯文本表示?因为差异工具基于存在纯文本的假设。我们的眼球也是如此。为什么XmlReader?您可以使用 SAX,它非常节省内存,但XmlReader效率更高。至于那个纯文本文件的精确规格......你只是没有包含足够的信息。
  • 将纯文本文件保存到某个临时目录。
  • 使用命令行差异实用程序(如 GnuWin32 diff)来获取一些差异输出。是的,我知道,不是纯粹和适当的,但开箱即用,无需编码。如果你熟悉一些C#差异API(我不熟悉),那么当然,请改用该API。
  • 删除临时文件。(或者,如果要重用它们,可以选择保留它们。