Kotej

How to compare two XML files without the formatting noise

Published · Alexandre Vazquez

You export the same configuration twice, or run the same transformation on two servers, and the diff says almost every line changed. Look closer and nothing did: one file is indented with tabs, the other with two spaces; one serializer writes id before name, the other the other way round. A text diff can't tell those apart from a real change, so the one value that actually differs is buried under hundreds of lines of noise.

Why a line diff is the wrong tool for XML

A line diff compares characters. XML is a tree, and many different strings describe the same tree:

To compare what two documents say, both have to be parsed and compared as trees.

The command-line way: canonicalize, then diff

If you have xmllint (part of libxml2), you can normalize both files with Canonical XML before diffing:

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

Canonical XML sorts attributes and normalizes empty elements and quoting, which removes a good part of the noise. It has two limits worth knowing: it keeps the whitespace between elements (so re-indented files still differ: pass both through xmllint --format first), and it keeps the order of every element, so a list that came out in a different order still shows up as changed.

Repeated elements: list or set?

That last point is the hard one. In most configuration and data files, a run of repeated elements, like the <dependency> entries of a pom.xml or the <item> lines of an order, is a set: the order they were written in doesn't matter, and a tool that regenerates the file may well shuffle them. But a sequence of differently named elements usually does carry meaning: <street> before <city> is part of the format.

Kotej's XML comparison follows exactly that rule: siblings with the same name are compared as a set, and differently named siblings keep their order. Attribute order, whitespace between elements and namespace prefixes are ignored, while element names, namespaces, attribute values and text are compared exactly. If the order of a repeated list does matter in your format, switch the file to the text comparison and you get a classic line diff.

Comparing XML in Kotej

  1. Open Kotej's XML diff and pick the two files, or drop them on each side. Any extension that holds XML works: .xml, .xsd, .xsl, .wsdl, pom.xml, .svg, .plist.
  2. The verdict is one of three: identical (same bytes), equivalent (same tree, different formatting) or different.
  3. When they differ, open the file to see the changes side by side, as a unified diff, or word by word.

The files are parsed in your browser and never uploaded, which matters when the XML is a production configuration or a customer's data. The same comparison works on two whole folders, or two ZIP or JAR files, applied to every XML file inside them.

A common case: checking a migration

Equivalence is exactly the question when you change the thing that produces the XML: a new library version, a new serializer, a rewritten XSLT. You don't want the same bytes; you want the same document. Generate the output with the old and the new version, compare them as XML, and only real changes remain. There is a step-by-step guide for XSLT migrations.

XML diff that compares meaning, not formatting. Free, no account, and nothing is uploaded: everything is compared in your browser.

More guides