Comparer deux fichiers XML et voir ce qui a changé

Le moyen le plus rapide de comparer deux fichiers XML est de les coller tous les deux dans un outil de diff côte à côte, de les formater de la même manière et de lire les lignes mises en évidence. La comparaison est la partie facile. C'est le bruit qui déroute : des attributs réorganisés, des espaces entre les balises et des préfixes de namespace peuvent faire que deux fichiers qui signifient la même chose semblent n'avoir rien en commun.

Ce guide explique comment obtenir un diff XML propre et fiable. Nous verrons pourquoi deux documents équivalents s'éloignent sur le papier, quelles méthodes valent la peine d'être connues, et un exemple concret à suivre. Si vous voulez juste l'outil, notre page de comparaison XML fait tout cela dans le navigateur.

Pourquoi les fichiers XML sont trompeusement difficiles à comparer

XML a une grammaire stricte (voir la spécification XML du W3C), mais il laisse aux auteurs beaucoup de latitude sur la mise en page du texte. Deux documents peuvent décrire exactement les mêmes données et différer octet par octet. Un diff de texte brut ne comprend rien de tout cela, alors il signale tout.

Voici le fait clé à retenir : en XML, l'ordre des attributs d'un élément n'est pas significatif. Le XML Information Set traite les attributs comme un ensemble non ordonné. Ainsi <user id="7" role="admin"/> et <user role="admin" id="7"/> portent la même information, même si un diff de lignes les peint en rouge et vert. L'ordre des éléments, en revanche, a généralement de l'importance.

Ça ressemble à un changement, mais en général ça n'en est pas un
Ce que vous voyez dans le diffEst-ce un vrai changement ?Que faire
Attributs dans un ordre différentNon, l'ordre des attributs n'est pas significatifCanonicalisez les deux côtés
Indentation de 2 vs 4 espacesNonFormatez les deux de la même façon
Espaces entre les élémentsEn général nonFormatez, ou supprimez les espaces non significatifs
<br/> vs <br></br>Non, même élément videCanonicalisez les deux côtés
Un préfixe de namespace différent pour le même URINon, les préfixes sont des étiquettes arbitrairesComparez par URI de namespace, pas par préfixe
Éléments enfants dans un ordre différentEn général oui, l'ordre des éléments compteInvestiguez, c'est probablement réel

Cette dernière ligne est celle à surveiller. L'ordre des attributs est libre, mais l'ordre des éléments enfants fait partie du document dans la plupart des schémas. Si vous voulez le détail de la façon dont un parseur voit tout cela, MDN propose une solide référence sur l'analyse de XML avec DOMParser.

Quatre façons de comparer du XML et quand utiliser chacune

Il n'y a pas de meilleure méthode unique. Cela dépend de l'emplacement des fichiers et de ce que vous cherchez à apprendre. Voici comment se comparent les options courantes.

MéthodeIdéal pourEffortComprend le XML ?
Inspection visuellePetits fichiers, un ou deux élémentsFaibleNon, c'est vous le parseur
Outil de diff en ligneVérifications rapides, coller de n'importe oùFaibleAvec le formatage, oui
Ligne de commande (xmllint)Fichiers sur disque, scripting, forme canoniqueMoyenOui, avec --c14n
IDE ou git diffFichiers déjà dans un dépôtFaible si commitéBasé sur les lignes par défaut

Pour la plupart des gens, un outil de navigateur l'emporte en rapidité : rien à installer, et vous pouvez coller un fragment directement depuis un fichier de configuration ou une réponse SOAP. Le hic, c'est le bruit de formatage, que nous traitons ensuite. Si vous vivez dans le terminal, xmllint de libxml2 est l'outil à connaître.

La comparaison propre la plus rapide, étape par étape

Voici la routine que j'utilise quand quelqu'un me tend deux fichiers de configuration et demande « qu'est-ce qui est différent ? ». Cela prend environ quinze secondes.

  1. Ouvrez l'outil de comparaison XML.
  2. Collez l'original à gauche, la nouvelle version à droite.
  3. Cliquez sur Formater des deux côtés pour qu'ils partagent la même indentation.
  4. Repérez les vraies différences. Le vert est ajouté, le rouge est supprimé, et une valeur modifiée apparaît comme une de chaque.
  5. Ignorez les lignes qui ne sont qu'un réordonnancement d'attributs ou des espaces.

L'étape trois est l'essentiel de l'astuce. Une fois que les deux documents utilisent la même indentation, il ne reste plus qu'à mettre en évidence ce qui a vraiment changé. Notre moteur de diff est bâti sur le diff-match-patch de Google, qui compare d'abord ligne par ligne pour rester rapide même sur de longs fichiers.

Un exemple concret

Supposons que vous révisiez un changement dans une config de service. Voici l'avant :

<user id="7" role="editor">
  <name>Ada Lovelace</name>
  <active>true</active>
  <seats>3</seats>
</user>

Et voici l'après, tel qu'un collègue vous l'a remis :

<user role="admin" id="7">
  <name>Ada Lovelace</name>
  <active>true</active>
  <seats>5</seats>
  <team>platform</team>
</user>

Mettez-les dans un diff de lignes brut et la toute première ligne semble modifiée, parce que id et role ont échangé leur place. Formatez les deux, comparez par le sens, et la vraie histoire est courte :

Ce qui a vraiment changé
NœudAvantAprèsChangement
@roleeditoradminModifié
seats35Modifié
teamplatformAjouté
@id77Aucun changement (juste déplacé)
nameAda LovelaceAda LovelaceAucun changement

Trois vraies modifications : une montée de rôle, un nombre de sièges et un nouvel élément d'équipe. L'échange d'attributs était du bruit. Cette promotion de editor à admin est exactement le genre de chose que vous voulez attraper en revue, et c'est facile à manquer quand c'est enterré sous une ligne que le diff a signalée à tort.

XML canonique : la bonne façon d'ignorer le bruit

Formater les deux côtés gère l'indentation, mais il existe un standard conçu exactement pour ce problème. Le XML canonique, défini par le W3C dans Canonical XML 1.1, réécrit un document sous une seule forme normalisée : attributs triés, éléments vides développés, espaces dans les balises normalisés, et attributs par défaut rendus explicites. Deux documents équivalents produisent une sortie canonique identique. C'est l'équivalent XML du tri des clés JSON.

xmllint --c14n old.xml > old.c14n.xml
xmllint --c14n new.xml > new.c14n.xml
diff old.c14n.xml new.c14n.xml

Maintenant diff ne signale que le contenu qui a réellement changé, parce que les deux fichiers ont été normalisés de la même manière. Si vous voulez juste une indentation lisible plutôt que la forme canonique stricte, xmllint --format file.xml le formate, ce qui est l'équivalent terminal d'un clic sur Formater dans le navigateur.

Namespaces : la partie qui embrouille tout le monde

Les namespaces XML permettent à deux documents d'utiliser le même vocabulaire avec des étiquettes de préfixe différentes. <ns1:user> lié à un URI et <u:user> lié au même URI sont le même élément ; le préfixe n'est qu'un surnom local. Un diff de texte voit ns1 contre u et signale un changement qui n'en est pas un. La solution est de comparer par l'URI du namespace plutôt que par le préfixe, ce qui est précisément ce que fait la canonicalisation. La spécification Namespaces in XML est la référence si vous avez besoin de trancher un débat à ce sujet.

Pièges courants à surveiller

PiègePourquoi ça mordSolution
Encodage des caractèresUn fichier UTF-8 et un UTF-16 peuvent contenir le même texte mais différer octet par octetNormalisez l'encodage ; la déclaration XML l'indique
Références d'entités&amp; et un & littéral peuvent tous deux apparaître pour le même caractèreCanonicalisez, ce qui résout les entités de façon cohérente
CDATA vs texte échappé<![CDATA[a<b]]> et a&lt;b sont le même contenu textuelComparez la valeur analysée, pas les octets bruts
Espaces significatifsÀ l'intérieur de xml:space="preserve", les espaces comptent et ne doivent pas être supprimésNe rognez pas à l'aveugle ; respectez xml:space
Balises auto-fermantes<x/> et <x></x> sont identiquesCanonicalisez pour que les deux s'affichent de la même façon

Diff de texte vs diff structurel

Tout ce qui précède est un diff de texte : rapide, visuel et parfait pour une personne qui lit un changement. Un diff structurel va plus loin et décrit le changement en termes d'arbre XML : cet attribut a changé, cet élément enfant a été inséré à ce chemin. Vous voulez un diff structurel quand un programme doit appliquer le changement ou quand l'ordre des éléments n'a vraiment pas d'importance et que vous voulez l'ignorer. Pour la revue quotidienne, un diff de texte de deux documents formatés suffit largement.

Outils connexes

Le XML est rarement le seul format que vous manipulez. Si vous comparez des charges utiles d'API, la comparaison JSON applique la même idée au JSON. Les pages balisées sont plus faciles à lire sur la page de comparaison HTML, et les paramètres d'environnement s'alignent bien sur l'outil de comparaison de config.

Questions fréquentes

Comparer des fichiers XML en ligne les téléverse-t-il quelque part ?
Sur comparetext.org, le diff s'exécute dans votre navigateur. Les deux fichiers XML sont comparés par JavaScript sur votre propre machine, donc rien n'est envoyé à un serveur à moins que vous ne cliquiez explicitement sur Enregistrer ou Partager. C'est donc sûr pour les fichiers de configuration, les messages SOAP et d'autres données que vous ne voudriez pas coller dans un site qui téléverse à chaque frappe.
Pourquoi mes deux fichiers XML affichent-ils chaque ligne comme différente ?
C'est presque toujours le formatage, pas de vrais changements. Un fichier est minifié ou indenté avec des tabulations, l'autre avec deux espaces, ou les attributs sont dans un ordre différent. Cliquez sur Formater des deux côtés pour qu'ils utilisent la même indentation. Après cela, le diff se réduit généralement à la poignée de valeurs qui ont vraiment changé. Pour une normalisation plus stricte, canonicalisez d'abord les deux fichiers avec xmllint --c14n.
L'ordre des attributs compte-t-il lors de la comparaison de XML ?
Non. En XML, les attributs d'un élément forment un ensemble non ordonné, donc <a x="1" y="2"/> et <a y="2" x="1"/> sont équivalents. Un diff de texte brut ne le sait pas et signalera le réordonnancement comme un changement. Le XML canonique trie les attributs dans un ordre fixe, donc canonicaliser les deux côtés avant de comparer fait disparaître le faux positif. L'ordre des éléments, en revanche, est généralement significatif.
Comment comparer du XML en ignorant les préfixes de namespace ?
Les préfixes de namespace sont des étiquettes locales pour un URI de namespace, donc ns1:user et u:user liés au même URI sont le même élément. Pour comparer correctement, normalisez par URI plutôt que par préfixe. Le plus simple est de canonicaliser les deux documents avec xmllint --c14n, qui réécrit les liaisons de namespace de façon cohérente, puis de comparer les résultats. Un diff de texte brut ne peut pas le faire seul.
Puis-je comparer de gros fichiers XML sans que la page ne se fige ?
Oui, jusqu'à un certain point. Un diff en mode ligne reste rapide sur des fichiers de milliers de lignes parce qu'il compare d'abord des lignes entières au lieu de chaque caractère. Les très gros fichiers (plusieurs mégaoctets) sont mieux gérés avec un outil en ligne de commande comme xmllint ou git diff, qui diffuse les données. Pour tout ce que vous pouvez faire défiler confortablement dans un navigateur, un diff en ligne est l'option la plus rapide.
Quelle est la différence entre un diff de texte et un diff structurel de XML ?
Un diff de texte compare les fichiers ligne par ligne, de la même façon qu'il comparerait deux dissertations. Un diff structurel comprend l'arbre XML, donc il sait qu'un attribut réordonné n'est pas un changement et peut signaler un élément inséré par son chemin. Les diffs de texte sont plus rapides et suffisants pour la plupart des revues une fois les deux côtés formatés. Les diffs structurels importent quand un programme doit appliquer le changement ou quand vous voulez ignorer l'ordre des éléments.

Prêt à essayer ? Collez vos fichiers dans l' outil de comparaison XML et voyez ce qui a changé.