如何从 2 个 XML 文件中删除重复元素
本文关键字:删除 元素 文件 XML | 更新日期: 2023-09-27 18:31:36
我有一个XML,我正在解析我的数据库,这个XML大小约为10MB,它包含数百万个元素。
每 30-60 秒更新一次,但只有几个元素,而不是全部。
为了以最快的方式将其解析到数据库,我开发了一个函数来从 2 个 XML 文件中删除重复元素,代码如下:
XDocument doc2 = XDocument.Parse(tempDoc.ToString());
var doc1 = new XDocument();
try
{
doc1 = XDocument.Load(bookieName + ".xml");
}
catch
{ }
try
{
var dict1 = doc1.Descendants("event").Select(el => el.ToString()).ToList();
var dict2 = doc1.Descendants("event").Select(el => el.ToString()).ToList();
foreach (var elem in dict1)
{
if (dict2.Contains(elem))
{
if (dict2.Find(x => x == elem).ToString() == dict1.Find(x => x == elem).ToString())
{
doc2.Descendants("event").Where(x => x.ToString() == elem).Remove();
}
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return doc2;
问题是,它适用于小型XML文件,但对于大型XML文件(10MB),2-5分钟需要100%的CPU。
您知道如何改进它并使其更好吗?
我有点绝望。
谢谢!
听起来你只希望删除doc2
中的元素,如果它们也存在于doc1
中,而不是相反。
面临的问题是您正在执行非常低效的搜索。如果您有几百万条记录,您实际上是在搜索几百万平方记录。
相反,你应该使用字典,而不是列表,来大大加快你的算法。
试试这个:
var dict1 = doc1.Descendants("event").ToDictionary(x => x.ToString(), x => x);
var dict2 = doc2.Descendants("event").ToDictionary(x => x.ToString(), x => x);
var xs = dict1.Keys.Intersect(dict2.Keys).Select(x => dict2[x]);
foreach (var x in xs)
{
x.Remove();
}
return doc2;
是的,就是这样。我已经在一些虚拟数据广告上对此进行了测试,它工作正常。
文档1:
<doc>
<event>bar</event>
<event>foo</event>
</doc>
初始文档2:
<doc>
<event>foo</event>
<event>qaz</event>
</doc>
最终文档2:
<doc>
<event>qaz</event>
</doc>
您可以通过在添加元素之前检查元素是否存在于数据库中来解决。
并且您希望使用 xml 读取器,以便可以在读取时进行分析(以获得最佳性能)
看起来你正在与两件事作斗争:
- 对于这种任务,XML是一个糟糕的选择(但我知道它可能不是你的选择)
- 将整个文档读成
XDocument
(或XmlDocument
)是昂贵且不必要的
要摆脱 (2),请尝试使用较低级别的方法XmlReader
(这可能还不够)或更低级别的方法,如 Java-nese SAX
或 Perl-ish XML:Twig
,它们为您提供基于事件的 XML 解析而无需构建文档结构 - 但我不知道这样的 .net 库。有一个用于 .NET 的 SAX 解析器端口,但我不知道它有多好。
当然,您可以节省大量时间保留以前解析的文档中的数据,而只解析新文档(但我相信您知道这一点)
你现在要做的是,对于字典 1 中这数百万个事件中的每一个,你迭代字典 2 中的数百万个事件,将字典 1 中的每个事件与字典 2 中的每个事件进行比较。这进行了数千亿次比较!这不是必需的。将第一个 XML 中的所有事件放入字典。然后,对于第二个 XML 中的每个事件,查看字典中是否也存在相同的事件。如果是,请将其删除。在字典中搜索比在第一个 XML 中遍历数百万个事件中的每一个要快得多,并且也会使您的程序更快。