使用 LINQ to XML 以编程方式获取 2 xml 文件之间的所有差异
use LINQ to XML to Programmatically get all differences between 2 xml files
我正在使用 c sharp 5.0 并使用 LINQ to XML 我尝试以编程方式获取 2 个 xml 文件之间的差异
我的第一个文件很简单:
<?xml version="1.0" encoding="UTF-8" ?>
<table name="MYTABLE">
<columns>
<column name="MY_ID" type="NUMBER"/>
<column name="M_NAME" type="VARCHAR2" />
<column name="MY_PARENT_ID" type="VARCHAR2" />
<column name="MY_CAPTION" type="VARCHAR2" />
</columns>
</table>
我的第二个 xml 文件很简单:
<?xml version="1.0" encoding="UTF-8" ?>
<table name=" MYTABLE ">
<columns>
<column name="MY_ID" type="NUMBER"/>
<column name="M_NAME" type="VARCHAR2" />
<column name="MY_PARENT_ID" type="NUMBER" />
</columns>
</table>
我的代码很简单:
XDocument doc1 = XDocument.Load(@"Path\table1.xml");
XDocument doc2 = XDocument.Load(@"Path\table2.xml");
var cols1 = doc1.Descendants("column") ;
var cols2 = doc2.Descendants("column") ;
var itemsOnFirstFileOnly = cols1.Except(cols2);
var itemsOnSecondFileOnly = cols2.Except(cols1);
但令我惊讶的是,itemsOnFirstFileOnly 返回了 table1.xml 中存在的所有列(不仅是 MY_PARENT_ID 和 MY_CAPTION),itemsOnSecondFileOnly 返回了 [=24 中存在的所有列=](不仅是 MY_PARENT_ID),所以为什么 Except 不能按预期工作?
您必须在 Column
-class 上实施 Equals
,以便 Except
知道两个 Columns
何时相等:
class Column
{
bool Equals(object other)
{
// ...
// skip further checks for simplicity
// ...
Column o = (Column) other;
return o.Name == this.Name && o.Type == this.Type ;
}
}
如果您不实施此方法,Except
将只检查引用相等性,这永远不会是真的,因为您的列来自不同的上下文(在您的情况下是文件)。
编辑:当您比较 XNodes
时,事情要容易得多,因为您可以使用 XNodeEqualityComparer
-class,它有自己的 Equals
-实现满足您的需求 here。因此以下应该有效:
var itemsOnFirstFileOnly = cols1.Except(cols2, new XNodeEqualityComparer());
您可以使用 Linq 执行此操作:
var itemsOnFirstFileOnly = cols1.Where(x => !cols2.Select(y => y.Attribute("name").Value).Contains(x.Attribute("name").Value));
var itemsOnSecondFileOnly = cols2.Where(x => !cols1.Select(y => y.Attribute("name").Value).Contains(x.Attribute("name").Value));
基本上在上面的代码中:
- 选择
name
属性的值
- 比较这些名称
- Returns
XElement
个名称在其他集合中丢失的实例。
您还可以将 XElement
转换为字符串,这会考虑属性:
XDocument doc = XDocument.Parse(xml);
XDocument doc2 = XDocument.Parse(xml2);
var diffs = doc.Descendants().Select(e => e.ToString())
.Except(doc2.Descendants().Select(e => e.ToString()));
foreach (var e in diffs)
{
Console.WriteLine(e);
Console.WriteLine();
}
考虑到列,这 returns 仅
<column name="MY_PARENT_ID" type="VARCHAR2" />
<column name="MY_CAPTION" type="VARCHAR2" />
我正在使用 c sharp 5.0 并使用 LINQ to XML 我尝试以编程方式获取 2 个 xml 文件之间的差异 我的第一个文件很简单:
<?xml version="1.0" encoding="UTF-8" ?>
<table name="MYTABLE">
<columns>
<column name="MY_ID" type="NUMBER"/>
<column name="M_NAME" type="VARCHAR2" />
<column name="MY_PARENT_ID" type="VARCHAR2" />
<column name="MY_CAPTION" type="VARCHAR2" />
</columns>
</table>
我的第二个 xml 文件很简单:
<?xml version="1.0" encoding="UTF-8" ?>
<table name=" MYTABLE ">
<columns>
<column name="MY_ID" type="NUMBER"/>
<column name="M_NAME" type="VARCHAR2" />
<column name="MY_PARENT_ID" type="NUMBER" />
</columns>
</table>
我的代码很简单:
XDocument doc1 = XDocument.Load(@"Path\table1.xml");
XDocument doc2 = XDocument.Load(@"Path\table2.xml");
var cols1 = doc1.Descendants("column") ;
var cols2 = doc2.Descendants("column") ;
var itemsOnFirstFileOnly = cols1.Except(cols2);
var itemsOnSecondFileOnly = cols2.Except(cols1);
但令我惊讶的是,itemsOnFirstFileOnly 返回了 table1.xml 中存在的所有列(不仅是 MY_PARENT_ID 和 MY_CAPTION),itemsOnSecondFileOnly 返回了 [=24 中存在的所有列=](不仅是 MY_PARENT_ID),所以为什么 Except 不能按预期工作?
您必须在 Column
-class 上实施 Equals
,以便 Except
知道两个 Columns
何时相等:
class Column
{
bool Equals(object other)
{
// ...
// skip further checks for simplicity
// ...
Column o = (Column) other;
return o.Name == this.Name && o.Type == this.Type ;
}
}
如果您不实施此方法,Except
将只检查引用相等性,这永远不会是真的,因为您的列来自不同的上下文(在您的情况下是文件)。
编辑:当您比较 XNodes
时,事情要容易得多,因为您可以使用 XNodeEqualityComparer
-class,它有自己的 Equals
-实现满足您的需求 here。因此以下应该有效:
var itemsOnFirstFileOnly = cols1.Except(cols2, new XNodeEqualityComparer());
您可以使用 Linq 执行此操作:
var itemsOnFirstFileOnly = cols1.Where(x => !cols2.Select(y => y.Attribute("name").Value).Contains(x.Attribute("name").Value));
var itemsOnSecondFileOnly = cols2.Where(x => !cols1.Select(y => y.Attribute("name").Value).Contains(x.Attribute("name").Value));
基本上在上面的代码中:
- 选择
name
属性的值 - 比较这些名称
- Returns
XElement
个名称在其他集合中丢失的实例。
您还可以将 XElement
转换为字符串,这会考虑属性:
XDocument doc = XDocument.Parse(xml);
XDocument doc2 = XDocument.Parse(xml2);
var diffs = doc.Descendants().Select(e => e.ToString())
.Except(doc2.Descendants().Select(e => e.ToString()));
foreach (var e in diffs)
{
Console.WriteLine(e);
Console.WriteLine();
}
考虑到列,这 returns 仅
<column name="MY_PARENT_ID" type="VARCHAR2" />
<column name="MY_CAPTION" type="VARCHAR2" />