一种比较两个 XML 文件并创建另一个具有差异的文件的快速方法
Posted
技术标签:
【中文标题】一种比较两个 XML 文件并创建另一个具有差异的文件的快速方法【英文标题】:A fast way to compare two XML files and create another one with differences 【发布时间】:2021-08-04 12:18:40 【问题描述】:我的朋友只想将产品差异上传到他的网上商店。所以我的想法是比较 XML 文件并仅提取更改。因此我创建了这个:
部分 XML 文件(请注意,此 XML 有更多元素,但我已将它们排除在外):
<?xml version="1.0" encoding="UTF-8"?>
<artikli>
<artikal>
<id>1039282</id>
<sifra>42640</sifra>
<naziv><![CDATA[Bluetooth zvucnik za tablet IYIGLE X7 crni]]></naziv>
</artikal>
<artikal>
<id>1048331</id>
<sifra>48888</sifra>
<naziv><![CDATA[Bluetooth zvucnik REMAX RB-M15 crni]]></naziv>
</artikal>
</artikli>
C# 脚本
static IEnumerable<XElement> StreamRootChildDoc(string uri)
using (XmlReader reader = XmlReader.Create(uri))
reader.MoveToContent();
while (!reader.EOF)
if (reader.NodeType == XmlNodeType.Element && reader.Name == "artikal")
XElement el = XElement.ReadFrom(reader) as XElement;
if (el != null)
yield return el;
else
reader.Read();
void ProcessFiles()
try
IEnumerable<XElement> posle = from el in StreamRootChildDoc(@"lisic2.xml")
select el;
IEnumerable<XElement> pre = from el in StreamRootChildDoc(@"lisic1.xml")
select el;
XmlDocument doc = new XmlDocument();
//(1) the xml declaration is recommended, but not mandatory
XmlDeclaration xmlDeclaration = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
XmlElement root = doc.DocumentElement;
doc.InsertBefore(xmlDeclaration, root);
//(2) string.Empty makes cleaner code
XmlElement element1 = doc.CreateElement(string.Empty, "artikli", string.Empty);
doc.AppendChild(element1);
int count_files = 0;
foreach (XElement node_posle in posle)
count_files++;
var node_pre = pre.First(child => child.Element("id").Value == node_posle.Element("id").Value);
if (node_pre != null)
string pre_Value = node_pre.Value.Replace("\t", ""); ;
string posle_Value = node_posle.Value.Replace("\t", ""); ;
if (pre_Value != posle_Value)
var reader = node_posle.CreateReader();
reader.MoveToContent();
XmlElement element2 = doc.CreateElement(string.Empty, "artikal", reader.ReadInnerXml());
element1.AppendChild(element2);
doc.Save("document.xml");
finally
这可行,但在 10000 条通过记录之后,速度为每秒 18 条记录,在 14000 - 12 条记录/秒之后。有没有其他方法可以加快速度?
更新
现在,我将尝试更快地移动到已检查 XML 的相应 ID。
【问题讨论】:
"可以改进吗?" -- 你打开一个分析器,看看为什么它很慢。我们无法为您猜测 我建议使用像 BenchMarkDotNet 这样的分析器来分析你的代码。使用分析中的信息来确定最大改进的领域。但是,根据个人经验,通过查看您的代码,对性能的追求将以可读性为代价,因为您的许多 LINQ 操作都需要扩展。 为了像这样在原地分析预先存在的代码,我会选择内置的 VS 分析器(在 CPU 模式下)或 PerfMon。 BenchmarkDotNet 不会告诉您为什么您的代码很慢,但可以很好地比较两个备选方案 为什么不直接使用超越比较? XmlReader 又旧又慢。您可以在一个指令中对 xml linq 执行相同操作:XDocument = doc = XDocument.Load(uri); ListXmlReader
不是“又老又慢”——它是一个低级的流式 XML 解析器,而像 XDocument
这样的高级框架就是 built on top of!
【参考方案1】:
一种方法是使用 XmlDocument,因为 XML 很小(22000 个产品),所以可以使用它。
void ProcessXMLDocument()
SetControlEnabled(btStart, false);
Stopwatch sw = new Stopwatch();
sw.Start();
try
XmlDocument sada = new XmlDocument();
sada.Load(tbPathSada.Text);
XmlDocument pre = new XmlDocument();
pre.Load(tbPathOdPre.Text);
XmlDocument doc = new XmlDocument();
//(1) the xml declaration is recommended, but not mandatory
XmlDeclaration xmlDeclaration = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
XmlElement root = doc.DocumentElement;
doc.InsertBefore(xmlDeclaration, root);
//(2) string.Empty makes cleaner code
XmlElement element1 = doc.CreateElement(string.Empty, "artikli", string.Empty);
doc.AppendChild(element1);
root = sada.DocumentElement;
XmlNodeList nodes = root.SelectNodes("artikal");
int count_files = 0;
foreach (XmlNode nodeSada in nodes)
count_files++;
try
SetControlText(lbBlokova, count_files.ToString());
TimeSpan elapsed = sw.Elapsed;
var files_per_sec = Math.Floor((double)count_files / (double)elapsed.TotalSeconds);
SetControlText(lbPerSecond, files_per_sec.ToString());
SetControlText(lbTime, elapsed.ToString(@"hh\:mm\:ss"));
catch (Exception ex2)
var idSada = nodeSada.SelectSingleNode("id").InnerText.Trim();
var nodePre = pre.DocumentElement.SelectSingleNode("artikal[id='" + idSada + "']");
if (nodePre != null)
string pre_Value = nodePre.InnerXml.Replace("\t", ""); ;
string posle_Value = nodeSada.InnerXml.Replace("\t", ""); ;
if (pre_Value != posle_Value)
XmlNode importNode = doc.ImportNode(nodeSada, true);
element1.AppendChild(importNode);
else
XmlNode importNode = doc.ImportNode(nodeSada, true);
element1.AppendChild(importNode);
doc.Save("razlika.xml");
finally
sw.Stop();
SetControlEnabled(btStart, true);
通过这种方式,我设法提高了@10000 条记录 => 140 条记录/秒和@14000 => 104 条记录/秒
【讨论】:
以上是关于一种比较两个 XML 文件并创建另一个具有差异的文件的快速方法的主要内容,如果未能解决你的问题,请参考以下文章