在 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>
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。
- 删除临时文件。(或者,如果要重用它们,可以选择保留它们。