我正在比较两个xml,我必须打印差异。如何使用LINQ实现此目的。 我知道我可以使用Microsoft的XML diff补丁,但我更喜欢使用LINQ。如果您有任何其他想法,我将实施
//第一个Xml
<Books>
<book>
<id="20504" image="C01" name="C# in Depth">
</book>
<book>
<id="20505" image="C02" name="ASP.NET">
</book>
<book>
<id="20506" image="C03" name="LINQ in Action ">
</book>
<book>
<id="20507" image="C04" name="Architecting Applications">
</book>
</Books>
//第二个Xml
<Books>
<book>
<id="20504" image="C011" name="C# in Depth">
</book>
<book>
<id="20505" image="C02" name="ASP.NET 2.0">
</book>
<book>
<id="20506" image="C03" name="LINQ in Action ">
</book>
<book>
<id="20508" image="C04" name="Architecting Applications">
</book>
</Books>
我想比较这两个xml和打印结果。
Issued Issue Type IssueInFirst IssueInSecond
1 image is different C01 C011
2 name is different ASP.NET ASP.NET 2.0
3 id is different 20507 20508
答案 0 :(得分:2)
以下是解决方案:
//sanitised xmls:
string s1 = @"<Books>
<book id='20504' image='C01' name='C# in Depth'/>
<book id='20505' image='C02' name='ASP.NET'/>
<book id='20506' image='C03' name='LINQ in Action '/>
<book id='20507' image='C04' name='Architecting Applications'/>
</Books>";
string s2 = @"<Books>
<book id='20504' image='C011' name='C# in Depth'/>
<book id='20505' image='C02' name='ASP.NET 2.0'/>
<book id='20506' image='C03' name='LINQ in Action '/>
<book id='20508' image='C04' name='Architecting Applications'/>
</Books>";
XDocument xml1 = XDocument.Parse(s1);
XDocument xml2 = XDocument.Parse(s2);
//get cartesian product (i think)
var result1 = from xmlBooks1 in xml1.Descendants("book")
from xmlBooks2 in xml2.Descendants("book")
select new {
book1 = new {
id=xmlBooks1.Attribute("id").Value,
image=xmlBooks1.Attribute("image").Value,
name=xmlBooks1.Attribute("name").Value
},
book2 = new {
id=xmlBooks2.Attribute("id").Value,
image=xmlBooks2.Attribute("image").Value,
name=xmlBooks2.Attribute("name").Value
}
};
//get every record that has at least one attribute the same, but not all
var result2 = from i in result1
where (i.book1.id == i.book2.id
|| i.book1.image == i.book2.image
|| i.book1.name == i.book2.name) &&
!(i.book1.id == i.book2.id
&& i.book1.image == i.book2.image
&& i.book1.name == i.book2.name)
select i;
foreach (var aa in result2)
{
//you do the output :D
}
两个linq语句可能都可以合并,但我把它作为练习留给你。
答案 1 :(得分:2)
为了好玩,grega g阅读问题的一般解决方案。为了说明我对这种方法的反对意见,我为'PowerShell in Action'引入了一个“正确”的条目。
string s1 = @"<Books>
<book id='20504' image='C01' name='C# in Depth'/>
<book id='20505' image='C02' name='ASP.NET'/>
<book id='20506' image='C03' name='LINQ in Action '/>
<book id='20507' image='C04' name='Architecting Applications'/>
<book id='20508' image='C05' name='PowerShell in Action'/>
</Books>";
string s2 = @"<Books>
<book id='20504' image='C011' name='C# in Depth'/>
<book id='20505' image='C02' name='ASP.NET 2.0'/>
<book id='20506' image='C03' name='LINQ in Action '/>
<book id='20508' image='C04' name='Architecting Applications'/>
<book id='20508' image='C05' name='PowerShell in Action'/>
</Books>";
XDocument xml1 = XDocument.Parse(s1);
XDocument xml2 = XDocument.Parse(s2);
var res = from b1 in xml1.Descendants("book")
from b2 in xml2.Descendants("book")
let issues = from a1 in b1.Attributes()
join a2 in b2.Attributes()
on a1.Name equals a2.Name
select new
{
Name = a1.Name,
Value1 = a1.Value,
Value2 = a2.Value
}
where issues.Any(i => i.Value1 == i.Value2)
from issue in issues
where issue.Value1 != issue.Value2
select issue;
报告以下内容:
{ Name = image, Value1 = C01, Value2 = C011 }
{ Name = name, Value1 = ASP.NET, Value2 = ASP.NET 2.0 }
{ Name = id, Value1 = 20507, Value2 = 20508 }
{ Name = image, Value1 = C05, Value2 = C04 }
{ Name = name, Value1 = PowerShell in Action, Value2 = Architecting Applications }
请注意,最后两个条目是20508错字与其他正确的20508条目之间的“冲突”。
答案 2 :(得分:1)
你想要的操作是一个Zip,用于配对你的两本书中的相应元素。那个运算符是added in .NET 4.0,但是我们可以通过使用Select来获取书籍索引并加入其中来伪造它:
var res = from b1 in xml1.Descendants("book")
.Select((b, i) => new { b, i })
join b2 in xml2.Descendants("book")
.Select((b, i) => new { b, i })
on b1.i equals b2.i
然后我们将使用第二个连接来按名称比较属性的值。请注意,这是一个内连接;如果你确实想要包含一个或另一个缺少的属性,你将不得不做更多的工作。
select new
{
Row = b1.i,
Diff = from a1 in b1.b.Attributes()
join a2 in b2.b.Attributes()
on a1.Name equals a2.Name
where a1.Value != a2.Value
select new
{
Name = a1.Name,
Value1 = a1.Value,
Value2 = a2.Value
}
};
结果将是嵌套集合:
foreach (var b in res)
{
Console.WriteLine("Row {0}: ", b.Row);
foreach (var d in b.Diff)
Console.WriteLine(d);
}
或者每本书获得多行:
var report = from r in res
from d in r.Diff
select new { r.Row, Diff = d };
foreach (var d in report)
Console.WriteLine(d);
报告以下内容:
{ Row = 0, Diff = { Name = image, Value1 = C01, Value2 = C011 } }
{ Row = 1, Diff = { Name = name, Value1 = ASP.NET, Value2 = ASP.NET 2.0 } }
{ Row = 3, Diff = { Name = id, Value1 = 20507, Value2 = 20508 } }