Zum Inhalt springen
jsonbeautifiers
Deutsch

JSON vergleichen

Vergleicht zwei Dokumente nach Struktur, sodass Umformatieren und Schlüsselreihenfolge unsichtbar bleiben.

Original
Geändert

Nichts, was Sie einfügen, verlässt Ihren Browser. Die connect-src Erlaubnisliste macht daraus eine Garantie des Browsers statt eines Versprechens. Selbst überprüfen

Hier werden zwei Dokumente nach Struktur verglichen, nicht nach Zeilen. Formatieren Sie eines um, sortieren Sie seine Schlüssel, ändern Sie die Einrückung: Der Diff bleibt leer, weil nichts davon die Daten verändert hat.

Ein Text-Diff auf JSON ist genau deshalb nahezu nutzlos. Serialisieren Sie ein Dokument mit einer anderen Bibliothek neu, und jede Zeile meldet sich als geändert, während sich tatsächlich nichts geändert hat.

Was als Unterschied zählt

Vier Arten von Änderung, jede mit einem JSON Pointer auf die exakte Stelle.

Hinzugefügt
Ein Schlüssel oder Element, das rechts vorhanden ist und links nicht.
Entfernt
Links vorhanden, rechts nicht.
Geändert
In beiden vorhanden, mit einem anderen Wert desselben Typs.
Typ geändert
In beiden vorhanden, mit einem anderen Typ. Das lohnt sich zu trennen, denn eine Zahl, die zur Zeichenkette wurde, ist meist ein Serialisierungsfehler und keine Datenänderung.

Wie Arrays verglichen werden und warum das zählt

Arrays sind der schwierige Teil jedes strukturellen Diffs, und es gibt keine einzige richtige Antwort.

Positionsweise zu vergleichen ist für ein Tupel fester Gestalt korrekt und für eine Liste katastrophal. Fügen Sie am Anfang eines Arrays mit tausend Elementen eines ein, und jede folgende Position meldet sich als geändert - der eine echte Unterschied verschwindet unter tausend falschen.

Dieses Werkzeug fährt stattdessen einen Durchgang über die längste gemeinsame Teilfolge, sodass eine Einfügung auch als Einfügung gemeldet wird. Das kostet Zeit proportional zum Produkt beider Längen, also fällt es oberhalb einer Schwelle auf den positionsweisen Vergleich zurück und sagt das in den Hinweisen. Es verschlechtert sich nie stillschweigend.

Was bewusst kein Unterschied ist

Die Schlüsselreihenfolge
JSON-Objekte sind laut Spezifikation ungeordnet. Zwei Dokumente mit denselben Mitgliedern in anderer Reihenfolge sind dasselbe Dokument.
Leerraum und Einrückung
Für einen Parser bedeutungslos, hier also unsichtbar.
0 und -0
Unter Object.is verschieden, als JSON-Zahlen identisch.

How to do this in code

Struktureller Vergleich im Code.

sh jq

Die erste Zeile ist die, die man sich merkt. Erst die Schlüssel zu sortieren nimmt einem Text-Diff den größten Teil seines Rauschens.

# Sort keys recursively, then diff the text. Cheap and
# surprisingly effective for small documents.
diff <(jq -S . a.json) <(jq -S . b.json)

# Keys present in one and not the other
jq -n --slurpfile a a.json --slurpfile b b.json \
  '($a[0] | paths) - ($b[0] | paths)'
py Python
from deepdiff import DeepDiff

diff = DeepDiff(a, b, ignore_order=True)
print(diff)

# Standard library only, for a shallow comparison
changed = {k for k in a.keys() | b.keys() if a.get(k) != b.get(k)}
js JavaScript

JSON Patch ist das Standardformat, um einen JSON-Diff zu übertragen, und seine Pfade sind RFC-6901-Pointer wie die, die dieses Werkzeug meldet.

import { compare } from 'fast-json-patch';

// RFC 6902 JSON Patch: a list of operations that turns a into b
const patch = compare(a, b);
// [{ op: 'replace', path: '/user/name', value: 'Priya' }]
go Go

go-cmp ist die Standardwahl in Go-Tests und erzeugt gut lesbare Ausgaben für verschachtelte Strukturen.

import "github.com/google/go-cmp/cmp"

if d := cmp.Diff(a, b); d != "" {
    t.Errorf("mismatch (-want +got):\n%s", d)
}

Häufige Fragen

Warum zeigt das Umsortieren von Schlüsseln keinen Unterschied?
Weil RFC 8259 ein Objekt als ungeordnete Sammlung definiert. In der Praxis bewahrt jeder Parser die Einfügereihenfolge, und Diffs, die darauf beruhen, testen die Serialisierung statt der Daten.
Kann ich Felder wie Zeitstempel ignorieren?
Ja. Einen Pfad zu ignorieren nimmt ihn ganz aus dem Vergleich heraus - so vergleicht man zwei API-Antworten, die sich nur in requestId und generatedAt unterscheiden.
Was ist ein JSON Pointer?
RFC 6901: ein durch Schrägstriche getrennter Pfad wie /users/0/email. Innerhalb eines Schlüssels müssen zwei Zeichen escapt werden: ~ wird zu ~0 und / wird zu ~1. Jede hier gemeldete Änderung trägt einen, sodass Sie die Stelle programmatisch ansprechen können.