C# 比较两个XML文件&;在C中使用XMLDiff生成第三个#

C# 比较两个XML文件&;在C中使用XMLDiff生成第三个#,c#,xml,xslt,xpath,diff,C#,Xml,Xslt,Xpath,Diff,我试图编写一个简单的算法来读取两个具有完全相同的节点和结构的XML文件,但不一定是子节点中相同的数据,也不一定是相同的顺序。如何使用Microsoft的XMLDiff.DLL创建一个简单的实现来创建第三个临时XML,即前两个XML之间的差异 MSDN上的XML差异: 要比较的两个不同XML文件的示例XML代码: <?xml version="1.0" encoding="utf-8" ?> <Stats Date="2011-01-01"> <Player

我试图编写一个简单的算法来读取两个具有完全相同的节点和结构的XML文件,但不一定是子节点中相同的数据,也不一定是相同的顺序。如何使用Microsoft的XMLDiff.DLL创建一个简单的实现来创建第三个临时XML,即前两个XML之间的差异

MSDN上的XML差异:

要比较的两个不同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>

到目前为止,这就是我所知道的,但是结果是垃圾。。。请注意,对于每个“玩家”节点,前三个孩子不必进行比较。。。如何实现这一点?

有两种即时解决方案:

解决方案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>
<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>

克罗斯比
矿井
C
39
32
33
20
29
10
1.
3.
0
154
20.8
21:54
22.6
生成所需的结果文档

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

39
32
33
20
29
10
1.
3.
0
154
20.8
21:54
22.6
解决方案2。

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


约翰·史密斯
纽约
D
38
32
33
15
29
10
1.
4.
0
158
20.8
21:54
22.6
-----------------------
当此转换应用于与上述相同的第一个文档时,将生成正确的diffgram

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

39
20
3.
154
-----------------------
38
15
4.
158
这是如何工作的

<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>
<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>
  • 转换应用于第一个文档,将第二个文档作为参数传递

  • 这将生成一个XML文档,其中只有叶元素节点的值与第二个文档中相应的叶元素节点的值不同

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

  • 这将生成第二个diffgram:一个XML文档,其唯一的叶元素节点是与第一个文档中对应的叶元素节点具有不同值**的节点


  • 好的。。。最后,我选择了一个纯C#解决方案来比较这两个XML文件,而不使用XML Diff/Patch.dll,甚至不需要使用XSL转换。不过,在下一步中,我将需要XSL转换,以便将Xml转换为HTML以供查看,但我只使用System.Xml和System.Xml.XPath实现了一个算法

    这是我的算法:

    private void CompareXml(string file1, string file2)
    {
        // Load the documents
        XmlDocument docXml1 = new XmlDocument();
        docXml1.Load(file1);
        XmlDocument docXml2 = new XmlDocument();
        docXml2.Load(file2);
    
    
        // Get a list of all player nodes
        XmlNodeList nodes1 = docXml1.SelectNodes("/Stats/Player");
        XmlNodeList nodes2 = docXml2.SelectNodes("/Stats/Player");
    
        // Define a single node
        XmlNode node1;
        XmlNode node2;
    
        // Get the root Xml element
        XmlElement root1 = docXml1.DocumentElement;
        XmlElement root2 = docXml2.DocumentElement;
    
        // Get a list of all player names
        XmlNodeList nameList1 = root1.GetElementsByTagName("Name");
        XmlNodeList nameList2 = root2.GetElementsByTagName("Name");
    
        // Get a list of all teams
        XmlNodeList teamList1 = root1.GetElementsByTagName("Team");
        XmlNodeList teamList2 = root2.GetElementsByTagName("Team");
    
        // Create an XmlWriterSettings object with the correct options. 
        XmlWriter writer = null;
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.Indent = true;
        settings.IndentChars = ("  ");
        settings.OmitXmlDeclaration = false;
    
        // Create the XmlWriter object and write some content.
        writer = XmlWriter.Create(StatsFile.XmlDiffFilename, settings);
        writer.WriteStartElement("StatsDiff");
    
    
        // The compare algorithm
        bool match = false;
        int j = 0;
    
        try 
        {
            // the list has 500 players
            for (int i = 0; i < 500; i++)
            {
                while (j < 500 && match == false)
                {
                    // There is a match if the player name and team are the same in both lists
                    if (nameList1.Item(i).InnerText == nameList2.Item(j).InnerText)
                    {
                        if (teamList1.Item(i).InnerText == teamList2.Item(j).InnerText)
                        {
                            match = true;
                            node1 = nodes1.Item(i);
                            node2 = nodes2.Item(j);
                            // Call to the calculator and Xml writer
                            this.CalculateDifferential(node1, node2, writer);
                            j = 0;
                        }
                    }
                    else
                    {
                        j++;
                    }
                }
                match = false;
    
            }
            // end Xml document
            writer.WriteEndElement();
            writer.Flush();
        }
        finally
        {
            if (writer != null)
                writer.Close();
        }
    }
    
    private void CompareXml(字符串文件1,字符串文件2)
    {
    //加载文档
    XmlDocument docXml1=新的XmlDocument();
    docXml1.Load(file1);
    XmlDocument docXml2=新的XmlDocument();
    docXml2.Load(file2);
    //获取所有播放器节点的列表
    XmlNodeList nodes1=docXml1.SelectNodes(“/Stats/Player”);
    XmlNodeList nodes2=docXml2.SelectNodes(“/Stats/Player”);
    //定义单个节点
    XmlNode节点1;
    XmlNode节点2;
    //获取根Xml元素
    xmlementroot1=docXml1.DocumentElement;
    xmlementroot2=docXml2.DocumentElement;
    //获取所有玩家姓名的列表
    XmlNodeList nameList1=root1.GetElementsByTagName(“名称”);
    XmlNodeList nameList2=root2.GetElementsByTagName(“名称”);
    //获取所有团队的列表
    XmlNodeList teamList1=root1.GetElementsByTagName(“团队”);
    XmlNodeList teamList2=root2.GetElementsByTagName(“团队”);
    //使用正确的选项创建XmlWriterSettings对象。
    XmlWriter=null;
    XmlWriterSettings=新的XmlWriterSettings();
    settings.Indent=true;
    settings.IndentChars=(“”);
    settings.OmitXmlDeclaration=false;
    //创建XmlWriter对象并编写一些内容。
    writer=XmlWriter.Create(StatsFile.XmlDiffFilename,设置);
    WriteStarteElement(“StatsDiff”);
    //比较算法
    布尔匹配=假;
    int j=0;
    尝试
    {
    //名单上有500名球员
    对于(int i=0;i<500;i++)
    {
    而(j<500&&match==false)
    {
    //如果两个列表中的球员姓名和球队相同,则存在匹配
    if(nameList1.Item(i).InnerText==nameList2.Item(j).InnerText)
    {
    if(teamList1.Item(i).InnerText==teamList2.Item(j).InnerText)
    {
    匹配=真;
    节点1=节点1.第(i)项;
    节点2=节点2.项目(j);
    //调用计算器和Xml编写器
    这个。计算差异(node1,node2,writer);
    j=0;
    }
    }
    其他的
    {
    j++;
    }
    }
    匹配=假;
    }
    //结束Xml文档
    writer.writeedelement();
    writer.Flush();
    }
    最后
    {
    if(writer!=null)
    writer.Close();
    }
    }