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.
| Ce que vous voyez dans le diff | Est-ce un vrai changement ? | Que faire |
|---|---|---|
| Attributs dans un ordre différent | Non, l'ordre des attributs n'est pas significatif | Canonicalisez les deux côtés |
| Indentation de 2 vs 4 espaces | Non | Formatez les deux de la même façon |
| Espaces entre les éléments | En général non | Formatez, ou supprimez les espaces non significatifs |
<br/> vs <br></br> | Non, même élément vide | Canonicalisez les deux côtés |
| Un préfixe de namespace différent pour le même URI | Non, les préfixes sont des étiquettes arbitraires | Comparez par URI de namespace, pas par préfixe |
| Éléments enfants dans un ordre différent | En général oui, l'ordre des éléments compte | Investiguez, 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éthode | Idéal pour | Effort | Comprend le XML ? |
|---|---|---|---|
| Inspection visuelle | Petits fichiers, un ou deux éléments | Faible | Non, c'est vous le parseur |
| Outil de diff en ligne | Vérifications rapides, coller de n'importe où | Faible | Avec le formatage, oui |
Ligne de commande (xmllint) | Fichiers sur disque, scripting, forme canonique | Moyen | Oui, avec --c14n |
IDE ou git diff | Fichiers déjà dans un dépôt | Faible 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.
- Ouvrez l'outil de comparaison XML.
- Collez l'original à gauche, la nouvelle version à droite.
- Cliquez sur Formater des deux côtés pour qu'ils partagent la même indentation.
- 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.
- 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 :
| Nœud | Avant | Après | Changement |
|---|---|---|---|
@role | editor | admin | Modifié |
seats | 3 | 5 | Modifié |
team | — | platform | Ajouté |
@id | 7 | 7 | Aucun changement (juste déplacé) |
name | Ada Lovelace | Ada Lovelace | Aucun 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ège | Pourquoi ça mord | Solution |
|---|---|---|
| Encodage des caractères | Un fichier UTF-8 et un UTF-16 peuvent contenir le même texte mais différer octet par octet | Normalisez l'encodage ; la déclaration XML l'indique |
| Références d'entités | & et un & littéral peuvent tous deux apparaître pour le même caractère | Canonicalisez, ce qui résout les entités de façon cohérente |
| CDATA vs texte échappé | <![CDATA[a<b]]> et a<b sont le même contenu textuel | Comparez 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és | Ne rognez pas à l'aveugle ; respectez xml:space |
| Balises auto-fermantes | <x/> et <x></x> sont identiques | Canonicalisez 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:useretu:userlié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é.