Dans le cadre de la classe de base de certains tests unitaires approfondis, j'écris une fonction d'assistance qui compare de manière récursive les nœuds d'un objet XmlDocument à un autre en C # (.NET). Quelques exigences de ceci:
xsi:schemaLocation
et xmlns:xsi
, bien que j'aimerais pouvoir indiquer lesquels.InnerText
, mais pas les deux.Pendant que je rédige quelque chose ensemble: Quelqu'un at-il écrit un tel code et serait-il possible de le partager ici?
D'un côté, comment appelleriez-vous les premier et deuxième documents? Je me suis référé à eux comme "source" et "cible", mais je me sens mal puisque le source est ce que je veux que le cible ressemble, sinon je lève une exception.
Microsoft a une XML diff API que vous pouvez utiliser
J'ai parcouru une liste plus complète de solutions à ce problème aujourd'hui, je vais bientôt essayer l'une d'entre elles:
essayez XMLUnit . Cette bibliothèque est disponible pour Java et .Net
Comparer des documents XML est compliqué. Google pour xmldiff (il existe même une solution Microsoft) pour certains outils. J'ai résolu ce problème de deux manières. J'ai utilisé XSLT pour trier les éléments et les attributs (car ils apparaissaient parfois dans un ordre différent, ce qui ne m'intéressait pas), et filtrer les attributs que je ne voulais pas comparer, puis j'ai utilisé XML: : Diff ou XML :: SemanticDiff module Perl, ou bien imprimé chaque document avec chaque élément et attribut sur une ligne distincte, et en utilisant la ligne de commande Unix avec diff pour les résultats.
Ce code ne satisfait pas toutes vos exigences, mais c'est simple et je l'utilise pour mes tests unitaires. L'ordre des attributs n'a pas d'importance, mais l'ordre des éléments l'est aussi. Le texte interne de l'élément n'est pas comparé. J'ai également ignoré le cas lors de la comparaison des attributs, mais vous pouvez facilement le supprimer.
public bool XMLCompare(XElement primary, XElement secondary)
{
if (primary.HasAttributes) {
if (primary.Attributes().Count() != secondary.Attributes().Count())
return false;
foreach (XAttribute attr in primary.Attributes()) {
if (secondary.Attribute(attr.Name.LocalName) == null)
return false;
if (attr.Value.ToLower() != secondary.Attribute(attr.Name.LocalName).Value.ToLower())
return false;
}
}
if (primary.HasElements) {
if (primary.Elements().Count() != secondary.Elements().Count())
return false;
for (var i = 0; i <= primary.Elements().Count() - 1; i++) {
if (XMLCompare(primary.Elements().Skip(i).Take(1).Single(), secondary.Elements().Skip(i).Take(1).Single()) == false)
return false;
}
}
return true;
}
Une autre façon de faire serait:
Cela ne vous donnera pas l'emplacement exact de la différence, mais si vous voulez simplement savoir s'il y a une différence, il est facile de le faire sans bibliothèques tierces.
J'utilise ExamXML pour comparer des fichiers XML. Vous pouvez l'essayer .. Les auteurs, A7Soft, fournissent également une API permettant de comparer des fichiers XML.
https://github.com/CameronWills/FatAntelope Une autre bibliothèque alternative à l'API Microsoft XML Diff. Il dispose d'un algorithme de diff XML pour effectuer une comparaison non ordonnée de deux documents XML et produire une correspondance optimale.
C'est un port C # de l'algorithme X-Diff décrit ici: http://pages.cs.wisc.edu/~yuanwang/xdiff.html
Disclaimer: Je l'ai écrit :)
Non pertinent pour l'OP puisqu'il ignore actuellement l'ordre des enfants, mais si vous voulez une solution avec code uniquement, vous pouvez essayer XmlSpecificationCompare que j'ai plutôt mal orienté développé.
J'ai écrit cette feuille de comparaison basée sur XSLT 1.0 que vous comparez b.xml à l'entrée XML qui affiche les différences d'éléments dans l'entrée qui ne sont pas dans b.xml.
Pour comparer deux sorties XML lors de tests automatisés, j'ai trouvé XNode.DeepEquals
.
Compare les valeurs de deux nœuds, y compris les valeurs de tous les nœuds descendants.
Usage:
var xDoc1 = XDocument.Parse(xmlString1);
var xDoc2 = XDocument.Parse(xmlString2);
bool isSame = XNode.DeepEquals(xDoc1.Document, xDoc2.Document);
//Assert.IsTrue(isSame);
Référence: https://docs.Microsoft.com/en-us/dotnet/api/system.xml.linq.xnode.deepequals?view=netcore-2.2
Basé sur @Two Cents et utilisant ce lien XMLSorting i a créé mon propre XmlComparer
Comparer le programme XML
private static bool compareXML(XmlNode node, XmlNode comparenode)
{
if (node.Value != comparenode.Value)
return false;
if (node.Attributes.Count>0)
{
foreach (XmlAttribute parentnodeattribute in node.Attributes)
{
string parentattributename = parentnodeattribute.Name;
string parentattributevalue = parentnodeattribute.Value;
if (parentattributevalue != comparenode.Attributes[parentattributename].Value)
{
return false;
}
}
}
if(node.HasChildNodes)
{
sortXML(comparenode);
if (node.ChildNodes.Count != comparenode.ChildNodes.Count)
return false;
for(int i=0; i<node.ChildNodes.Count;i++)
{
string name = node.ChildNodes[i].LocalName;
if (compareXML(node.ChildNodes[i], comparenode.ChildNodes[i]) == false)
return false;
}
}
return true;
}
Trier le programme XML
private static void sortXML(XmlNode documentElement)
{
int i = 1;
SortAttributes(documentElement.Attributes);
SortElements(documentElement);
foreach (XmlNode childNode in documentElement.ChildNodes)
{
sortXML(childNode);
}
}
private static void SortElements(XmlNode rootNode)
{
for(int j = 0; j < rootNode.ChildNodes.Count; j++) {
for (int i = 1; i < rootNode.ChildNodes.Count; i++)
{
if (String.Compare(rootNode.ChildNodes[i].Name, rootNode.ChildNodes[1 - 1].Name) < 0)
{
rootNode.InsertBefore(rootNode.ChildNodes[i], rootNode.ChildNodes[i - 1]);
}
}
}
// Console.WriteLine(j++);
}
private static void SortAttributes(XmlAttributeCollection attribCol)
{
if (attribCol == null)
return;
bool changed = true;
while (changed)
{
changed = false;
for (int i = 1; i < attribCol.Count; i++)
{
if (String.Compare(attribCol[i].Name, attribCol[i - 1].Name) < 0)
{
//Replace
attribCol.InsertBefore(attribCol[i], attribCol[i - 1]);
changed = true;
}
}
}
}