Сравните два xml и распечатайте различие с помощью LINQ

Это должно сделать:

select(
SELECT col1
 FROM table1
 WHERE col2 = 'x'
 ORDER by col3
 FOR XML path('')
) as myName

Не симпатичный, но должен дать результат, в котором Вы нуждаетесь

8
задан dahlbyk 24 September 2009 в 14:15
поделиться

3 ответа

Вот решение:

//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, вероятно, можно было бы объединить, но я оставляю это в качестве упражнения для вас.

2
ответ дан 5 December 2019 в 23:15
поделиться

Ради интереса, общее решение проблемы, прочитанной Грегой Г. Чтобы проиллюстрировать свое возражение против этого подхода, я ввел «правильную» запись для «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
ответ дан 5 December 2019 в 23:15
поделиться

Здесь вам нужна операция Zip для объединения соответствующих элементов в две последовательности книг. Этот оператор добавлен в .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 } }
1
ответ дан 5 December 2019 в 23:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: