c# - 比较两个 XML 文件并在 C# 中使用 XMLDiff 生成第三个文件

标签 c# xml xslt xpath diff

我正在尝试编写一个简单的算法来读取两个节点和结构完全相同但子节点内的数据不一定相同且顺序不同的 XML 文件。我如何使用 Microsoft 的 XML Diff .DLL 创建一个简单的实现来创建第三个临时 XML 作为前两个 XML 之间的差异?

MSDN 上的 XML 差异:

XML Diff and Patch Tool

XML Diff and Patch GUI Tool

要比较的两个不同 XML 文件的示例 XML 代码:

<?xml version="1.0" encoding="utf-8" ?> 
<Stats Date="2011-01-01">
 <Player Rank="1">
  <Name>Sidney Crosby</Name> 
  <Team>PIT</Team> 
  <Pos>C</Pos> 
  <GP>39</GP> 
  <G>32</G> 
  <A>33</A> 
  <PlusMinus>20</PlusMinus> 
  <PIM>29</PIM> 
 </Player>
</Stats>

<?xml version="1.0" encoding="utf-8" ?> 
<Stats Date="2011-01-10">
 <Player Rank="1">
  <Name>Sidney Crosby</Name> 
  <Team>PIT</Team> 
  <Pos>C</Pos> 
  <GP>42</GP> 
  <G>35</G> 
  <A>34</A> 
  <PlusMinus>22</PlusMinus> 
  <PIM>30</PIM> 
 </Player>
</Stats>

想要的结果(两者的区别)

<?xml version="1.0" encoding="utf-8" ?> 
<Stats Date="2011-01-10">
 <Player Rank="1">
  <Name>Sidney Crosby</Name> 
  <Team>PIT</Team> 
  <Pos>C</Pos> 
  <GP>3</GP> 
  <G>3</G> 
  <A>1</A> 
  <PlusMinus>2</PlusMinus> 
  <PIM>1</PIM> 
 </Player>
</Stats>

在这种情况下,我可能会使用 XSLT 将生成的 XML“差异”文件转换为排序的 HTML 文件,但我还没有这样做。我想要做的就是在第三个 XML 文件中显示每个节点的每个数值的差异,从“GP”子节点开始。

我目前拥有的 C# 代码:

private void CompareXml(string file1, string file2)
{

    XmlReader reader1 = XmlReader.Create(new StringReader(file1));
    XmlReader reader2 = XmlReader.Create(new StringReader(file2));

    string diffFile = StatsFile.XmlDiffFilename;
    StringBuilder differenceStringBuilder = new StringBuilder();

    FileStream fs = new FileStream(diffFile, FileMode.Create);
    XmlWriter diffGramWriter = XmlWriter.Create(fs);

    XmlDiff xmldiff = new XmlDiff(XmlDiffOptions.IgnoreChildOrder |
                            XmlDiffOptions.IgnoreNamespaces |
                            XmlDiffOptions.IgnorePrefixes);
    bool bIdentical = xmldiff.Compare(file1, file2, false, diffGramWriter);

    diffGramWriter.Close();

    // cleaning up after we are done with the xml diff file
    File.Delete(diffFile);
}

这就是我目前所拥有的,但结果是垃圾...请注意,对于每个“玩家”节点,前三个 child NOT要进行比较...我如何实现这个?

最佳答案

有两个直接的解决方案:

解决方案 1

您可以先对这两个文档应用一个简单的转换,删除不应该比较的元素。然后,将两个文档的结果与您当前的代码进行比较。这是转换:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="Name|Team|Pos"/>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时:

<Stats Date="2011-01-01">
    <Player Rank="1">
        <Name>Sidney Crosby</Name>
        <Team>PIT</Team>
        <Pos>C</Pos>
        <GP>39</GP>
        <G>32</G>
        <A>33</A>
        <PlusMinus>20</PlusMinus>
        <PIM>29</PIM>
        <PP>10</PP>
        <SH>1</SH>
        <GW>3</GW>
        <Shots>0</Shots>
        <ShotPctg>154</ShotPctg>
        <TOIPerGame>20.8</TOIPerGame>
        <ShiftsPerGame>21:54</ShiftsPerGame>
        <FOWinPctg>22.6</FOWinPctg>
    </Player>
</Stats>

产生了想要的结果文件:

<Stats Date="2011-01-01">
   <Player Rank="1">
      <GP>39</GP>
      <G>32</G>
      <A>33</A>
      <PlusMinus>20</PlusMinus>
      <PIM>29</PIM>
      <PP>10</PP>
      <SH>1</SH>
      <GW>3</GW>
      <Shots>0</Shots>
      <ShotPctg>154</ShotPctg>
      <TOIPerGame>20.8</TOIPerGame>
      <ShiftsPerGame>21:54</ShiftsPerGame>
      <FOWinPctg>22.6</FOWinPctg>
   </Player>
</Stats>

解决方案 2.

这是一个完整的 XSLT 1.0 解决方案(仅为方便起见,转换代码中嵌入了第二个 XML 文档):

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:variable name="vrtfDoc2">
  <Stats Date="2011-01-01">
    <Player Rank="2">
        <Name>John Smith</Name>
        <Team>NY</Team>
        <Pos>D</Pos>
        <GP>38</GP>
        <G>32</G>
        <A>33</A>
        <PlusMinus>15</PlusMinus>
        <PIM>29</PIM>
        <PP>10</PP>
        <SH>1</SH>
        <GW>4</GW>
        <Shots>0</Shots>
        <ShotPctg>158</ShotPctg>
        <TOIPerGame>20.8</TOIPerGame>
        <ShiftsPerGame>21:54</ShiftsPerGame>
        <FOWinPctg>22.6</FOWinPctg>
    </Player>
  </Stats>
 </xsl:variable>

 <xsl:variable name="vDoc2" select=
  "document('')/*/xsl:variable[@name='vrtfDoc2']/*"/>

 <xsl:template match="node()|@*" name="identity">
  <xsl:param name="pDoc2"/>
  <xsl:copy>
   <xsl:apply-templates select="node()|@*">
    <xsl:with-param name="pDoc2" select="$pDoc2"/>
   </xsl:apply-templates>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="/">
  <xsl:apply-templates select="*">
   <xsl:with-param name="pDoc2" select="$vDoc2"/>
  </xsl:apply-templates>

  -----------------------

  <xsl:apply-templates select="$vDoc2">
   <xsl:with-param name="pDoc2" select="/*"/>
  </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="Player/*">
  <xsl:param name="pDoc2"/>
  <xsl:if test=
   "not(. = $pDoc2/*/*[name()=name(current())])">
   <xsl:call-template name="identity"/>
  </xsl:if>
 </xsl:template>

 <xsl:template match="Name|Team|Pos" priority="20"/>
</xsl:stylesheet>

当此转换应用于与上述相同的第一个文档时,会生成正确的差异图:

<Stats Date="2011-01-01">
   <Player Rank="1">
      <GP>39</GP>
      <PlusMinus>20</PlusMinus>
      <GW>3</GW>
      <ShotPctg>154</ShotPctg>
   </Player>
</Stats>

  -----------------------

  <Stats xmlns:xsl="http://www.w3.org/1999/XSL/Transform" Date="2011-01-01">
   <Player Rank="2">
      <GP>38</GP>
      <PlusMinus>15</PlusMinus>
      <GW>4</GW>
      <ShotPctg>158</ShotPctg>
   </Player>
</Stats>

这是如何运作的:

  1. 转换应用于第一个文档,将第二个文档作为参数传递。

  2. 这会生成一个 XML 文档,其唯一的叶元素节点与第二个文档中的相应叶元素节点具有不同的值

  3. 执行与上面 1. 中相同的处理,但这次是在第二个文档上,将第一个文档作为参数传递。

  4. 这会产生第二个 diffgram:一个 XML 文档,其唯一的叶元素节点与第一个文档中相应的叶元素节点具有不同的值**

关于c# - 比较两个 XML 文件并在 C# 中使用 XMLDiff 生成第三个文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4590214/

相关文章:

c# - 每次回发后的 Chrome realod 图像 - updatepanel

c# - JavaScript:来自 ASP.NET 代码隐藏的 Alert.Show(message)

c# - 方法有数组参数,将数组对象传递给参数

sql-server - 禁止重复列的 XML DML (Xpath) 查询。它应该在插入列之前测试它是否存在

c# - 如何在 C# 文件中使用 XML 而不是使用外部 XML 文件?

xml - GhostScript 在 ImageMagick 中的文件路径

xslt - 需要找到具有最大表格单元格数的表格行

xml - 在linux中格式化没有根节点的xml文件

xslt - 在哪里可以找到有关 XSLT 文件的优秀教程?

c# - 我什么时候应该使用 JSON 序列化以及为什么?