Comparer deux fichiers XML et en générer un troisième avec XMLDiff en C #

J’essaie d’écrire un algorithme simple pour lire deux fichiers XML avec exactement les mêmes nœuds et la même structure, mais pas nécessairement les mêmes données à l’intérieur des nœuds enfants et pas le même ordre. Comment puis-je créer une simple implémentation pour créer un troisième XML temporaire, la différence entre les deux premières, en utilisant le fichier XML Diff .DLL de Microsoft?

Diff XML sur MSDN:

Diff XML et outil de correction

Outil d’interface graphique XML Diff et Patch

Exemple de code XML des deux fichiers XML différents à comparer:

   Sidney Crosby PIT C 39 32 33 20 29      Sidney Crosby PIT C 42 35 34 22 30   

Résultat recherché (différence entre les deux)

    Sidney Crosby PIT C 3 3 1 2 1   

Dans ce cas, j’utiliserais probablement XSLT pour convertir le fichier XML “différentiel” résultant en un fichier HTML sortingé, mais je n’y suis pas encore. Tout ce que je veux, c’est afficher dans le troisième fichier XML la différence de chaque valeur numérique de chaque nœud, à partir du nœud enfant “GP”.

Code C # que j’ai jusqu’à présent:

 private void CompareXml(ssortingng file1, ssortingng file2) { XmlReader reader1 = XmlReader.Create(new SsortingngReader(file1)); XmlReader reader2 = XmlReader.Create(new SsortingngReader(file2)); ssortingng diffFile = StatsFile.XmlDiffFilename; SsortingngBuilder differenceSsortingngBuilder = new SsortingngBuilder(); FileStream fs = new FileStream(diffFile, FileMode.Create); XmlWriter diffGramWriter = XmlWriter.Create(fs); XmlDiff xmldiff = new XmlDiff(XmlDiffOptions.IgnoreChildOrder | XmlDiffOptions.IgnoreNamespaces | XmlDiffOptions.IgnorePrefixes); bool bIdentical = xmldiff.Compare(file1, file2, false, diffGramWriter); diffGramWriter.Close(); // cleaning up after we are done with the xml diff file File.Delete(diffFile); } 

C’est ce que j’ai eu jusqu’à présent, mais le résultat est décevant. Notez que pour chaque nœud “Player”, les trois premiers enfants ne doivent PAS être comparés … Comment puis-je mettre en œuvre cela?

Il y a deux solutions immédiates:

Solution 1

Vous pouvez d’abord appliquer une transformation simple aux deux documents afin de supprimer les éléments qui ne doivent pas être comparés. Ensuite, comparez les résultats dans deux documents – exactement avec votre code actuel. Voici la transformation:

           

Lorsque cette transformation est appliquée au document XML fourni :

   Sidney Crosby PIT C 39 32 33 20 29 10 1 3 0 154 20.8 21:54 22.6   

le document recherché recherché est produit :

   39 32 33 20 29 10 1 3 0 154 20.8 21:54 22.6   

Solution 2

Il s’agit d’une solution complète XSLT 1.0 (par souci de commodité, le deuxième document XML est incorporé dans le code de transformation):

       John Smith NY D 38 32 33 15 29 10 1 4 0 158 20.8 21:54 22.6                 -----------------------             

lorsque cette transformation est appliquée au même premier document que ci-dessus, les diffgrammes corrects sont générés

   39 20 3 154   -----------------------   38 15 4 158   

Comment ça marche :

  1. La transformation est appliquée sur le premier document , en transmettant le deuxième document en tant que paramètre.

  2. Cela produit un document XML dont les seuls nœuds d’élément feuille sont ceux dont la valeur est différente de celle des nœuds d’élément feuille correspondants du second document.

  3. Le même traitement est effectué comme en 1. ci-dessus, mais cette fois sur le deuxième document , en passant le premier document en paramètre.

  4. Cela produit un deuxième diffgramme : un document XML dont les seuls nœuds d’élément feuille sont ceux dont la valeur est différente ** des nœuds d’élément feuille correspondants dans le premier document.

D’accord … j’ai finalement opté avec une solution purement C # pour comparer les deux fichiers XML, sans utiliser XML Diff / Patch .dll et même sans avoir besoin d’utiliser des transformations XSL. J’aurai besoin de transformations XSL à la prochaine étape pour convertir le XML en HTML à des fins d’affichage, mais j’ai imaginé un algorithme n’utilisant que System.Xml et System.Xml.XPath.

Voici mon algorithme:

 private void CompareXml(ssortingng file1, ssortingng file2) { // Load the documents XmlDocument docXml1 = new XmlDocument(); docXml1.Load(file1); XmlDocument docXml2 = new XmlDocument(); docXml2.Load(file2); // Get a list of all player nodes XmlNodeList nodes1 = docXml1.SelectNodes("/Stats/Player"); XmlNodeList nodes2 = docXml2.SelectNodes("/Stats/Player"); // Define a single node XmlNode node1; XmlNode node2; // Get the root Xml element XmlElement root1 = docXml1.DocumentElement; XmlElement root2 = docXml2.DocumentElement; // Get a list of all player names XmlNodeList nameList1 = root1.GetElementsByTagName("Name"); XmlNodeList nameList2 = root2.GetElementsByTagName("Name"); // Get a list of all teams XmlNodeList teamList1 = root1.GetElementsByTagName("Team"); XmlNodeList teamList2 = root2.GetElementsByTagName("Team"); // Create an XmlWriterSettings object with the correct options. XmlWriter writer = null; XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; settings.IndentChars = (" "); settings.OmitXmlDeclaration = false; // Create the XmlWriter object and write some content. writer = XmlWriter.Create(StatsFile.XmlDiffFilename, settings); writer.WriteStartElement("StatsDiff"); // The compare algorithm bool match = false; int j = 0; try { // the list has 500 players for (int i = 0; i < 500; i++) { while (j < 500 && match == false) { // There is a match if the player name and team are the same in both lists if (nameList1.Item(i).InnerText == nameList2.Item(j).InnerText) { if (teamList1.Item(i).InnerText == teamList2.Item(j).InnerText) { match = true; node1 = nodes1.Item(i); node2 = nodes2.Item(j); // Call to the calculator and Xml writer this.CalculateDifferential(node1, node2, writer); j = 0; } } else { j++; } } match = false; } // end Xml document writer.WriteEndElement(); writer.Flush(); } finally { if (writer != null) writer.Close(); } } 

Résultats XML:

    Sidney Crosby PIT C 0 0 0 0 0 0 0 0 0 0 0 0 0 0   Steven Stamkos TBL C 1 0 0 0 0 2 0 0 0 0 4 -0,6000004 -0,09999847 0,09999847  [...]  

J'ai épargné pour montrer l'implémentation de la méthode CalculateDifferential (), c'est plutôt cryptique mais c'est rapide et efficace. Je pouvais ainsi obtenir les résultats souhaités sans utiliser d'autre référence que le ssortingct minimum, sans avoir à utiliser XSL ...

À l’aide de XSLT, j’ai écrit une solution XSLT 1.0 compatible Microsoft utilisant un algorithme de comparaison d’arborescence pour rechercher les différences entre deux fichiers xml. J’ai posté la feuille dans ma bibliothèque github. Il génère tous les nœuds avec des différences entre eux. Toutefois, s’il ne trouve pas de correspondance, il recherche les nœuds frères. La variable en haut de la feuille est l’endroit où vous définissez la feuille d’entrée à comparer.

C’est efficace avec seulement quelques limitations.

https://github.com/sflynn1812/xslt-diff