8
votes

Comparez deux XML et imprimez la différence à l'aide de LINQ

Je comparais deux XML et je dois imprimer la différence. Comment puis-je atteindre cet effet en utilisant LINQ? Je sais que je peux utiliser XML DIFF Patch par Microsoft, mais je préfère utiliser LINQ. Si vous avez une autre idée, je vais mettre en œuvre que

// premier xml p> xxx pré>

// second xml p> xxx pré> p > Je veux comparer ces deux xml et résultat d'impression comme celui-ci. P>

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


5 commentaires

Quelle est la complexité du XML? Si c'est juste root / record / @ attribu, il est probablement faisable.


Salut Marc C'est un exemple très simple dans Actuall XML son petit complexe binaire.


Est-ce que la différence que dans les valeurs et / ou les attributs ou peut également être différente?


Différence que dans les valeurs d'attributs (comme vous le voyez en question). la structure ne change jamais.


Donc, chaque fois qu'un attribut est identique à deux rangées, il devrait signaler deux autres attributs différents?


3 Réponses :


2
votes

Voici la solution:

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


5 commentaires

Je serais surpris que cela fonctionne réellement comme demandé si vous voulez vraiment une jointure croisée (produit cartésien)?


Oui ça marche. La prochaine fois que vous pouvez vérifier vous-même, avant de commenter. Permet maintenant de «revoir» votre solution.


Il produit le même résultat pour cet exemple défini, oui. Mais cela ne résout pas le problème général comme je le comprends. Par exemple, supposons que le livre de XML2 avec ID = 20508 était une faute de frappe et la prochaine entrée avait les données «réelles» 20508 dans chaque source. Votre solution rendrait deux rangées; le mien en retournerait un. Les deux réponses correctes en fonction de la question.


Bonjour Grega Qu'en est-il de si nous avons un livre qui manque d'abord XML ou deuxième XML, quelles lignes je dois ajouter au-dessus du code ci-dessus.


Vous voulez dire si un livre est seulement dans un XML et non dans l'autre? Que voulez-vous arriver que?



1
votes

L'opération que vous voulez ici est un zip pour jumeler des éléments correspondants dans vos deux séquences de livres. Cet opérateur est ajouté à .NET 4.0 , mais nous pouvons la simuler à l'aide de sélectionner les indices de livres et de se joindre à ce que:

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


2 commentaires

Eh bien, la chose avec ZIP est que cela rejoint le premier enregistrement de XML1 au premier enregistrement de XML2. Donc, si nous mélangions XML1 un peu - disons que nous allons basculer premier et deuxième nœuds - nous obtenons un résultat différent. C'est pourquoi vous avez besoin de jointure croisée. Il n'y a aucune raison d'assumer (de sa question et de ses commentaires) que seuls les nœuds correspondants devraient être comparés.


La question a été décrite comme une diff. Dans un ordre différent.



2
votes

Pour le plaisir, une solution générale à la lecture du problème de Grega G. Pour illustrer mon objection à cette approche, j'ai introduit une "entrée correcte" pour "PowerShell in Action".

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


1 commentaires

@Grega G Comment repérer les différences dans les valeurs d'attribut Lorsque vous avez 50 paires de valeur, devons-nous comparer par nom d'attribut pour chacun ou y a-t-il un meilleur moyen de faire de même. Merci..