问题描述
我有一个包含序列化对象的审核列表,我想比较它们并返回差异列表.通过比较",我的意思是我想返回元素文本已更改的位置,或添加节点的位置(因此它不在 Xml1 中,但在 Xml2 中 - 它不会以相反的方式发生)
I have an audit list full of serialized objects, and I'd like to compare them and return a list of the differences. By 'compare' I mean I want to return where the text for an element has changed, or where a node has been added (so its not in Xml1, but it is in Xml2- it won't happen the other way around)
示例 xml:
<HotelBookingView xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Id>119</Id>
<RoomId>1</RoomId>
<ChangeRequested>false</ChangeRequested>
<CourseBookings>
<CourseHotelLink>
<Id>0</Id>
</CourseHotelLink>
</CourseBookings>
</HotelBookingView>
标签的名称空间和名称/大小写不会改变.此示例中所有可以更改的是标签之间的值,以及CourseHotelLink"的数量(它是一个序列化列表).
The namespaces and the names/case of the tags will not change. All that can change in this sample is the values between the tags, and the number of 'CourseHotelLink's (its a serialized list).
我想要的最终结果是哪个节点已更改的列表 - 旧值和新值.
The final result I would like is a list of which node has changed- the old value and the new value.
比较它们的最佳选择是什么?我正在使用 .Net 4.0,所以 linq 是一个选项.我需要能够在不必知道所有节点的名称的情况下进行比较——尽管我只会比较两个相同类型的对象.我一直在尝试使用以下代码,但我无法调整它以找出文本中的更改以及额外的节点.
What is the best option to compare them? I am using .Net 4.0 so linq is an option. I need to be able to do the comparison without necessarily knowing the names of all the nodes- though I will only ever compare two objects of the same type. I have been trying to use the following code, but I can't manage to adapt it to pick out changes in text as well as extra nodes.
XmlDocument Xml1 = new XmlDocument();
XmlDocument Xml2 = new XmlDocument();
Xml1.LoadXml(list[1].Changes);
Xml2.LoadXml(list[2].Changes);
foreach (XmlNode chNode in Xml2.ChildNodes)
{
CompareLower(chNode);
}
protected void CompareLower(XmlNode aNode)
{
foreach (XmlNode chlNode in aNode.ChildNodes)
{
string Path = CreatePath(chlNode);
if (chlNode.Name == "#text")
{
//all my efforts at comparing text have failed
continue;
}
if (Xml1.SelectNodes(Path).Count == 0)
{
XmlNode TempNode = Xml1.ImportNode(chlNode, true);
//node didn't used to exist, this works- though doesn't return values
str = str + "New Node: " + TempNode.Name + ": " + TempNode.Value;
}
else
{
CompareLower(chlNode);
}
}
}
我的代码尝试很可能离我很远,还有更好的方法,欢迎提出任何建议!
Its likely my code attempts are miles off and there is a much better way to do, any suggestions welcome!
编辑添加:我最终使用了 MS Xml Diff Tool,以下代码生成了两个 xml 节点的大 html 表列表,其中的差异以绿色突出显示.所以它可能(虽然很疯狂)生成 html,然后对其进行排序以找到文本lightgreen"(突出显示的值),然后执行一些字符串格式以仅显示更改的子节点.
EDITTED to add: I ended up using the MS Xml Diff Tool, the following code produces a big html table listing of the two xml nodes, with the differences highlighted in green. So its possible (though insane) to produce the html, then sort through it to find the text 'lightgreen' (the highlighted value), then do some string formations to display only the changed child-node.
var node1 = XElement.Parse("Xml string 1 here").CreateReader();
var node2 = XElement.Parse("Xml string 2 here").CreateReader();
MemoryStream diffgram = new MemoryStream();
XmlTextWriter diffgramWriter = new XmlTextWriter(new StreamWriter(diffgram));
XmlDiff xmlDiff = new XmlDiff(XmlDiffOptions.IgnoreChildOrder);
xmlDiff.Algorithm = XmlDiffAlgorithm.Fast;
xmlDiff.Compare(node1, node2,diffgramWriter);
diffgram.Seek(0, SeekOrigin.Begin);
XmlDiffView xmlDiffView = new Microsoft.XmlDiffPatch.XmlDiffView();
StringBuilder sb = new StringBuilder();
TextWriter resultHtml = new StringWriter(sb);
xmlDiffView.Load("Xml string 1", new XmlTextReader(diffgram));
xmlDiffView.GetHtml(resultHtml);
resultHtml.Close();
推荐答案
使用 XMlDiff 是要走的路 - 证明它这里有一些工作代码.我正在使用你的 XML.如果 XML 不同(或无效),这可能不起作用.
Using XMlDiff is the way to go - to prove it here's some working code. I'm using your XML. If the XML is different (or invalid), this may not work.
原文:
var xml1 = @"<HotelBookingView xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
<Id>119</Id>
<RoomId>1</RoomId>
<ChangeRequested>false</ChangeRequested>
<CourseBookings>
<CourseHotelLink>
<Id>0</Id>
</CourseHotelLink>
</CourseBookings>
</HotelBookingView>";
CourseBookings
中的不同 Id
值:
var xml2 = @"<HotelBookingView xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
<Id>119</Id>
<RoomId>1</RoomId>
<ChangeRequested>false</ChangeRequested>
<CourseBookings>
<CourseHotelLink>
<Id>1</Id>
</CourseHotelLink>
</CourseBookings>
</HotelBookingView>";
创建阅读器的省力方式(如果需要,更改为 XDocument
):
Low effort way of creating readers (change to XDocument
if needed):
var node1 = XElement.Parse(xml1).CreateReader();
var node2 = XElement.Parse(xml2).CreateReader();
准备结果写入器:
var result = new XDocument();
var writer = result.CreateWriter();
做差异:
var diff = new Microsoft.XmlDiffPatch.XmlDiff();
diff.Compare(node1, node2, writer);
writer.Flush();
writer.Close();
result
现在是一个 XDocument
,其中包含差异摘要:
result
is now an XDocument
that contains a summary of the differences:
<xd:xmldiff version="1.0" srcDocHash="14506386314386767543" options="None" fragments="no" xmlns:xd="http://schemas.microsoft.com/xmltools/2002/xmldiff">
<xd:node match="1">
<xd:node match="4">
<xd:node match="1">
<xd:node match="1">
<xd:change match="1">1</xd:change>
</xd:node>
</xd:node>
</xd:node>
</xd:node>
</xd:xmldiff>
这篇关于比较 XML 片段和回报差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!