使用Linq检查XML文件是否有丢失或额外的记录

时间:2013-12-05 16:48:50

标签: c# xml linq-to-xml

我有两个XML文件(我称之为A和B),它们包含重复的记录,但其中一个文件可能有额外的记录,或者可能少一些。我需要编写一些Linq代码来比较两个文件,告诉我文件“A”是否有不在文件“B”中的记录。我还需要反向并选择文件“B”中但不在文件“A”中的记录。每个文件中的XML看起来类似于:

<importJob>
  <entities>
    <entity id="7eaab021-1c05-4385-b820-50aa619c9a99" >
      <field name="RuleTypeId" value="a29b9bce-d1f5-4c11-879f-f1a572b6ff0a" />
      <field name="Name" value="Group1" />
      <field name="Notes" />
      <field name="EntityId" value="14B03381-C09C-4B69-A749-F33A4B3F0305" />
      <field name="Selector" />
    </entity>
    <entity id="69cd0eab-d10d-46fb-b1a3-018fd9d6aa97" >
      <field name="RuleTypeId" value="a29b9bce-d1f5-4c11-879f-f1a572b6ff0a" />
      <field name="Name" value="Group2" />
      <field name="Notes" />
      <field name="EntityId" value="1eaab021-1c05-4385-b820-50aa619c9a99" />
      <field name="Selector" />
    </entity>
  </entities> 
</importJob>

需要对实体“id”属性进行比较。如果两个具有相同id的文件中都存在记录,则表示匹配。两者的“字段”值可能不同,但我仍然希望将其视为匹配。

假设上面的XML在文件“A”中并且以下XML在文件“B”中,我希望输出说记录“69cd0eab-d10d-46fb-b1a3-018fd9d6aa97”在文件“A”中但是不在文件“B”中。请注意,尽管记录“7eaab021-1c05-4385-b820-50aa619c9a99”的内容都不同,但id匹配,因此不应将其标记为不在文件“B”中

<importJob>
  <entities>
    <entity id="7eaab021-1c05-4385-b820-50aa619c9a99" >
      <field name="RuleTypeId" value="0eaab021-1c05-4385-b820-50aa619c9a99" />
      <field name="Name" value="Group9" />
      <field name="Notes" />
      <field name="EntityId" value="05e3b0d2-6f15-4c3e-b737-01ee5b1b1ae1" />
      <field name="Selector" value="1" />
    </entity>
    <entity id=" 96AA845C-2848-49E3-8BA6-F50F34F66749" >
      <field name="RuleTypeId" value="a29b9bce-d1f5-4c11-879f-f1a572b6ff0a" />
      <field name="Name" value="Group10" />
      <field name="Notes" />
      <field name="EntityId" value=" 53431D25-F7C4-4A8A-8E12-43F4D29BF46A" />
      <field name="Selector" />
    </entity>
  </entities> 
</importJob>

我开始使用这个Linq语句,但它查看整个节点。我尝试添加一个属性引用,但它不会构建。有人帮我解决这个问题吗?

var diff = fileA.Descendants("entity").Except(fileB.Descendants("entity"), new XNodeEqualityComparer());

2 个答案:

答案 0 :(得分:2)

首先 - 从两个文件中选择实体ID。您可以在投影查询时将id属性强制转换为Guid。这将返回guids的集合:

var idsA = xdocA.Descendants("entity").Select(e => (Guid)e.Attribute("id"));
var idsB = xdocB.Descendants("entity").Select(e => (Guid)e.Attribute("id"));

然后使用Enumerable.IntersectEnumerable.Except查找仅存在于第二序列中的序列和ID中的公共ID:

IEnumerable<Guid> inBothFiles = idsA.Intersect(idsB);
IEnumerable<Guid> onlyInFileB = idsB.Except(idsA);

答案 1 :(得分:0)

假设您将这两个文件都作为xDoc:

var aIds = fileA.Descendants("entity").Select(x=> x.Attribute("id").Value()).ToList();
var bIds = fileb.Descendants("entity").Select(x=> x.Attribute("id").Value()).ToList();
var noMatches = aIds.Select(x=> !bIds.Contains(x).Tolist();
noMatches.AddRange(bIds.Select(x=> !aIds.Contains(x).Tolist());

这将为您提供不匹配的ID列表,修改一下您可以得到您想要的(例如,选择一个新对象,即文件名和ID的NV对)。