【问题标题】:Compare XML fragments & return differences比较 XML 片段并返回差异
【发布时间】:2012-05-07 12:58:09
【问题描述】:

我有一个包含序列化对象的审核列表,我想比较它们并返回差异列表。通过“比较”,我的意思是我想返回元素文本已更改的位置,或添加节点的位置(因此它不在 Xml1 中,但在 Xml2 中 - 它不会以相反的方式发生)

示例 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”的数量(它是一个序列化列表)。

我想要的最终结果是哪个节点已更改的列表 - 旧值和新值。

比较它们的最佳选择是什么?我正在使用 .Net 4.0,所以 linq 是一个选项。我需要能够在不必知道所有节点的名称的情况下进行比较——尽管我只会比较两个相同类型的对象。我一直在尝试使用以下代码,但我无法调整它以找出文本中的更改以及额外的节点。

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);
        }
    } 
}

我的代码尝试很可能离我很远,还有更好的方法,欢迎提出任何建议!

编辑添加: 我最终使用了 MS Xml Diff Tool,以下代码生成了两个 xml 节点的大 html 表列表,其中的差异以绿色突出显示。所以它可能(虽然很疯狂)生成 html,然后对其进行排序以找到文本“lightgreen”(突出显示的值),然后执行一些字符串格式以仅显示更改的子节点。

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();

【问题讨论】:

  • 我还没有弄清楚如何让 MS Diff 和 Patch 获取 XML 字符串——我的 XML 来自数据库,我不想每次使用它时都必须创建文件...可能只是我很密集。
  • 您不需要创建文件,它带有许多重载来比较文件,XmlTextReader 或 XmlNode
  • 任何使用 XmlReaders 的尝试最终都会出现 XmlException 错误:根级别的数据无效。第 1 行,位置 1.',所以我假设序列化的对象不是非常有效的 XML。因此试图找到与 MS Patch 和 Diff 无关的解决方案!我知道它很重要,我希望对它施加足够的限制会让它更容易!还是我应该继续与 MS 工具作斗争?
  • 您示例中的片段是有效的 XML。如果不是(而且修复起来并不简单),那么任何比较都可能非常困难。我认为序列化的 XML 始终有效,因此它可能是您用来保存该文件以供测试使用的 编码

标签: c# xml compare


【解决方案1】:

使用 XMlDiff 是可行的方法 - 证明它这里有一些工作代码。我正在使用你的 XML。如果 XML 不同(或无效),这可能不起作用。

原文:

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):

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,其中包含差异摘要:

<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>

【讨论】:

  • 确实有效,谢谢!所以我只需要解析 diffgram 以使其能够显示诸如“CourseBookings Id 为 0,现在为 1”之类的内容,这应该很有趣!
  • 如果它回答了原始问题,请不要忘记接受 :-) 有关如何解释来自 xmldiff 的返回的大量信息。
  • 接受,谢谢!并且.. 有一些示例说明如何解释差异图以仅显示差异?我的弱 google-fu 什么也没找到
  • 尝试不同的问题并在此处链接,以便我查看。最好单独构图。
猜你喜欢
  • 2014-02-26
  • 1970-01-01
  • 1970-01-01
  • 2021-08-30
  • 2019-08-22
  • 1970-01-01
  • 1970-01-01
  • 2016-09-04
  • 2015-09-14
相关资源
最近更新 更多