我正在寻找一个基于Windows的差异工具,该工具可以向我展示两个XML文件之间的差异,但是这样做是基于树的而不是基于行的。
如果节已移到文件中完全不同的位置,则不应报告差异。
这两个文件应报告为“相同”:

<soapenv:Body>
  <mes:GetItem>
    <mes:ItemShape>
      <typ:BaseShape>IdOnly</typ:BaseShape>
      <typ:BodyType>Text</typ:BodyType>
      <typ:AdditionalProperties>
        <typ:FieldURI FieldURI="item:Subject" />
        <typ:FieldURI FieldURI="item:Categories" />
      </typ:AdditionalProperties>
    </mes:ItemShape>
    <mes:ItemIds>
      <typ:ItemId Id="AAMYAAA="/>
    </mes:ItemIds>
  </mes:GetItem>
</soapenv:Body>


<soapenv:Body>
  <mes:GetItem>
    <mes:ItemIds>
      <typ:ItemId Id="AAMYAAA="/>
    </mes:ItemIds>
    <mes:ItemShape>
      <typ:BodyType>Text</typ:BodyType>
      <typ:BaseShape>IdOnly</typ:BaseShape>
      <typ:AdditionalProperties>
        <typ:FieldURI FieldURI="item:Categories" />
        <typ:FieldURI FieldURI="item:Subject" />
      </typ:AdditionalProperties>
    </mes:ItemShape>
  </mes:GetItem>
</soapenv:Body>


当然,所有差异都应标记出来,最好是在并排视图中用指示器或连接不同部分的线来表示。

免费会很好。
可选地忽略名称空间会很好。

评论

免费XML比较工具的可能副本

@rrirower是的,但是它在那里关闭了:/ Stack Exchange具有关闭而不是迁移的趋势。

Jan,您是否尝试过Windows上最常见的差异程序(例如WinMerge2011),以查看它们是否具有该功能的选项? (请注意,自上次更新常规WinMerge以来,WinMerge2011进行了许多更新,即使名称暗示相反的意思。)

“报告为'相同'” ...仅当您坚持认为某些标签的顺序无关时,这些XML文件才是“相同”的。对于某些人来说,顺序确实很重要。您需要一个架构或其他信号来指示哪种情况,哪种标记。

@Mast我当前的工作不再需要这个,所以我把它放在了后面。不过,在我可以抽出时间的时候,仍然打算重新查看这篇文章。

#1 楼

从技术上讲,XML是不同的


是否具有空格
如果顺序不同
如果它们具有注释
如果它们具有处理指令与否
如果它们的编码不同
如果它们的名称空间不同

,但是您当然可以基于XML的语义信息来决定是否忽略它

Microsoft为此目的开发了XML Diff and Patch工具,您可以将其集成到自己的应用程序中。

注意:该工具安装为“ SQLXML Bulkload in “ .NET代码示例”,并附带需要自己进行编译的Visual Studio解决方案XmlDiffView.sln。 C#和Visual Studio Community Edition的一些基本编程知识应该是可以的。
之后,它提供了一个UI,可让您选择各种XML比较选项:



当我将其应用于您所问问题的2个XML时,它会引发异常。那是由于未定义的名称空间。删除命名空间后,它说:



评论


谢谢。我已对此答案表示赞同,但未将其标记为正确的答案。原因:GUI工具的结果窗口的界面很糟糕:比较两个大型XML文件时,差异窗口的宽度约为3000像素,包含所有相同的XML,并且没有滚动条。然后尝试找出两个55 MB的文件之间的区别;-(我不是Cx程序员,所以我无法适应该程序。

–user416
17年4月3日在12:16



@JanDoggen:是的,我同意,这是非常面向开发人员的。没有编程技能就很难使用它。

–托马斯·韦勒(Thomas Weller)
17年4月3日在12:23

@JanDoggen滚动条是一个很小的条,在窗口的右边缘只有几像素宽。我同意输出不是很好,但是它仍然是一个有用的工具。

– Suncat2000
17年8月3日在13:10

@ThomasWeller +1链接到BitBucket。我进行了编译,但没有运气,无法正常工作。

– Suncat2000
17年8月3日在13:12

#2 楼

专注于应该报告移动部分的部分,因为没有差异,使我想到了http://semanticmerge.com/,它不比较XML文件,而是C#和C代码。并且,由于它了解这些语言,因此能够显示代码是否移动并且未更改。

这导致了此问题的另一种解决方法:是否可以将XML转换为C#类,并且然后对结果代码进行语义合并?

如果尚未编写此工具,则一种可能的方法是将每个元素转换为类,并将每个属性(和主体文本)转换为该类中的字符串属性。如果要忽略名称空间,请让您的翻译人员在翻译过程中将其删除。

我翻译了给出的XML示例作为概念证明,并得到了以下内容:

class soapenv__Body {
  class mes__GetItem {
    class mes__ItemShape {
      class typ__BaseShape {
          string body="IdOnly";
      }
      class typ__BodyType {
          string body="Textus";
      }
      class typ__AdditionalProperties {
        class typ__FieldURI  {
            string FieldURI="item:Subject";
        }
        class typ__FieldURI  {
            string FieldURI="item:Categories"; 
        }
      }
    }
    class mes__ItemIds {
      class typ__ItemId {
          string Id="AAMYAAA=";
      }
    }
  }
}


然后我切换了mes:ItemIdsmes:ItemShape并将文本更改为Textus。在“语义合并”中比较了以下两个文件,并得到了以下图像:由M图标指示的文本。线条指示不同部分的移动/更改位置,并且可能实际看到它们是否存在差异。

请注意,即使理解C#代码,语义合并也不是严格限制在同一类上C的名称很不错,因为XML可以包含多个具有相同名称的节点。

摘要:即使元素移动,语义合并也可以正确地将XML标识为相同(或不相同),如果可以将XML转换为C#类结构。

评论


只是为了好玩,我尝试移动typ:FieldUri元素,并且语义合并正确地将它们标识为已移动。因此,可以正确检测到顺序,如果需要,您可以跟踪属性的顺序。

– Holroy
15年6月26日在21:36

#3 楼

从技术上讲,它们是不一样的(至少在xml中是这样),顺序很重要,除非在架构中明确指出了这一点。

以下内容仅比较结构,但可以扩展为查看属性,它们的值和文本

xmlstarlet el snippet1-with-namespaces.xml | sort > structure1.txt

xmlstarlet el snippet2-with-namespaces.xml | sort > structure2.txt

diff structure.txt structure2.txt


之后在您的代码片段上运行此命令,差异未显示差异,但存在有关名称空间的错误文本(可以忽略)。

#4 楼

我会推荐一个工具XiMpLe,它是XML编辑器的主要工具,但它也能够以一种安排良好的方式比较(和合并)xml文件。
您的示例经过比较并评估为相同。还有一个选项也可以解析名称空间。


#5 楼

目前,我正在为自己解决一个非常相似的问题。
不幸的是,我没有找到适合我的需要来生成xml比较的svg可视化效果的库。
所以只是为了好玩,并希望找到支持XmlXdiff库的人。
到目前为止,它不是项目符号证明库,仍在建设中,但这是您的示例代码段的结果:



产生此结果的代码:

    from XmlXdiff.XReport import DrawXmlDiff

    _xml1 = """<frame xmlns:soapenv="sn" xmlns:mes="meas" xmlns:typ="type">
    <soapenv:Body>
      <mes:GetItem>
        <mes:ItemShape>
          <typ:BaseShape>IdOnly</typ:BaseShape>
          <typ:BodyType>Text</typ:BodyType>
          <typ:AdditionalProperties>
            <typ:FieldURI FieldURI="item:Subject" />
            <typ:FieldURI FieldURI="item:Categories" />
          </typ:AdditionalProperties>
        </mes:ItemShape>
        <mes:ItemIds>
          <typ:ItemId Id="AAMYAAA="/>
        </mes:ItemIds>
      </mes:GetItem>
    </soapenv:Body>
    </frame>"""
    _xml2 = """<frame xmlns:soapenv="sn" xmlns:mes="meas" xmlns:typ="type">
    <soapenv:Body>
      <mes:GetItem>
        <mes:ItemIds>
          <typ:ItemId Id="AAMYAAA="/>
        </mes:ItemIds>
        <mes:ItemShape>
          <typ:BodyType>Text</typ:BodyType>
          <typ:BaseShape>IdOnly</typ:BaseShape>
          <typ:AdditionalProperties>
            <typ:FieldURI FieldURI="item:Categories" />
            <typ:FieldURI FieldURI="item:Subject" />
          </typ:AdditionalProperties>
        </mes:ItemShape>
      </mes:GetItem>
    </soapenv:Body>
    </frame>"""

    _path1 = '{}\..\..\tests\simple\xml1.xml'.format(getPath())
    _path2 = '{}\..\..\tests\simple\xml2.xml'.format(getPath())
    _out = '{}\..\..\tests\simple\xdiff.svg'.format(getPath())

    with open(_path1, "w") as f:
        f.write(_xml1)

    with open(_path2, "w") as f:
        f.write(_xml2)

    x = DrawXmlDiff(_path1, _path2)
    x.draw()
    x.saveSvg(_out)