Skip to main content

JSON Diff Viewer

Compare two JSON documents semantically. Detects added, removed and changed keys and array elements; ignores object key order.

Geprüft von · Zuletzt geprüft

Den JSON-Diff-Viewer verwenden

  1. Füge das linke (originale) Dokument in das erste Textfeld ein. Jedes gültige JSON funktioniert: eine API-Antwort, eine Konfigurationsdatei, eine Snapshot-Fixture oder ein einzelner primitiver Wert.
  2. Füge das rechte (geänderte) Dokument in das zweite Textfeld ein. Beide Seiten können eine beliebige Struktur haben; der Viewer vergleicht, was er vorfindet.
  3. Drücke Vergleichen. Das Zusammenfassungsfenster zeigt die Anzahl hinzugefügter, entfernter und ersetzter Einträge; die detaillierte Liste darunter zeigt eine Zeile pro Operation mit der Operationsart, einem JSONPointer-Pfad sowie den alten und neuen Werten.
  4. Ordne Objektschlüssel auf einer Seite neu an und führe den Vergleich erneut aus. Die Ausgabe bleibt gleich, weil die Reihenfolge von Objektschlüsseln kein JSON-Unterschied ist; dies ist das Killer-Feature gegenüber einem einfachen Text-Diff.
  5. Kopiere den Pfad einer beliebigen Operation, um ihn in jq, fast-json-patch oder einen anderen RFC-6901-Konsumenten einzuspeisen.

Was der Viewer intern tut

Beide Eingaben werden mit dem nativen JSON.parse geparst, das fehlerhafte JSON erkennt, bevor der Komparator läuft. Die Diff-Funktion traversiert beide Bäume parallel innerhalb von JsonDiff.logic.ts: Objektschlüssel werden nach Name abgeglichen (ein add, wenn die rechte Seite einen Schlüssel hat, den die linke nicht hat; ein remove für den umgekehrten Fall; ein replace, wenn beide Seiten den Schlüssel haben, die Werte aber unterschiedlich sind), Array-Elemente werden nach Index in Dokumentenreihenfolge abgeglichen. Primitive Werte verwenden strikte Gleichheit plus einen Deep-Equal-Helfer für verschachtelte Arrays und Objekte, sodass neu geordnete Unterobjekte nicht als Änderungen registriert werden.

Ausgabepfade folgen genau RFC 6901 (JSONPointer). Die Wurzel ist /, Kindschlüssel werden nach einem Schrägstrich angehängt, und die Sonderzeichen ~ und / werden zu ~0 und ~1 maskiert, sodass jede Zeichenfolge ein gültiger Zeiger werden kann. Dieses Format wird von RFC-6902-JSON-Patch-Dokumenten und jeder JSON-Patch-Bibliothek auf npm oder PyPI konsumiert, sodass die Diff-Ausgabe ohne zusätzliches Parsing in eine echte Patch-Pipeline portiert werden kann. Der gesamte Komparator ist eine reine Funktion mit Unit-Test-Abdeckung und ohne Laufzeitabhängigkeiten.

Ein praktisches Beispiel: Operationen lesen

Angenommen, die linke (originale) Payload ist ein Benutzerdatensatz und die rechte ist derselbe Datensatz nach einer Bearbeitung:

// links                         // rechts
{                                {
  "id": 42,                        "id": 42,
  "name": "Ada",                   "name": "Ada Lovelace",
  "roles": ["author"],             "roles": ["author", "admin"],
  "legacy": true                   "verified": true
}                                }

Der Vergleich erzeugt vier Operationen, jede mit einem JSONPointer-Pfad:

  • replace bei /name, alt "Ada", neu "Ada Lovelace" - gleicher Schlüssel, neuer Wert.
  • add bei /roles/1, neu "admin" - ein Array-Element am Index 1 hinzugefügt.
  • remove bei /legacy, alt true - Schlüssel nur auf der linken Seite vorhanden.
  • add bei /verified, neu true - Schlüssel nur auf der rechten Seite.

Beachte, dass /id keine Operation erzeugt, weil sein Wert unverändert ist, und das Neuanordnen von name und id die Ausgabe nicht ändern würde. Diese Stabilität bei der Neuanordnung von Schlüsseln macht den Diff für Konfigurationsdateien und API-Snapshots verwendbar, bei denen Autoren Schlüssel frei verschieben.

Wann dieses Werkzeug seinen Wert beweist

  • Überprüfen, was sich zwischen zwei Aufzeichnungen derselben API-Antwort geändert hat: die gestrige Payload vs. die heutige oder Staging vs. Produktion.
  • Vergleich zweier Konfigurationsdateien (Kubernetes-Manifeste, Terraform-Plan-Ausgabe, OpenAPI-Dokumente), bei denen Autoren Schlüssel beiläufig neu anordnen und ein Text-Diff 80 % Rauschen erzeugt.
  • Entdecken eines unerwarteten Feldes, das während eines Refactorings in eine Vitest- oder Jest-Snapshot-Fixture eingeschlichen ist, ohne dass sich die Form hätte ändern sollen.
  • Vergleichen der endgültigen Job-Ausgabe-JSONs zweier GitHub-Actions-Workflow-Läufe, um festzustellen, welcher Schritt einen Ausgabewert geändert hat.
  • Prüfen des Effekts einer Datenbankmigration auf eine serialisierte JSON-Spalte durch Export von Vor- und Nachher-Zeilen und Einfügen dieser.
  • Erstellen einer JSON-Patch-Pfadliste für einen nachgelagerten Patch-Konsumenten (einen CRDT-Replikator, eine Yjs-Synchronisierungsschicht, einen einfachen Webhook-Delta-Weiterleitungsdienst).

Häufige Fallstricke und Randfälle

  • Array-Ausrichtung ist indexbasiert, nicht LCS-basiert. Das Einfügen eines Elements am Anfang eines Arrays verschiebt jeden nachfolgenden Index und erscheint als Kette von Ersetzungen plus einem Hinzufügen. Dies ist die korrekte Semantik für indexbasierte Daten; für inhaltsbasierte Listen sortiere beide Seiten zuerst oder verwende jsondiffpatch.
  • Die Unterscheidung zwischen Zahl und Zeichenfolge ist relevant. {"id": 42} und {"id": "42"} registrieren als Ersetzen, weil JSON den Typ beibehält. Viele APIs wechseln diesen Typ beiläufig zwischen Versionen, und der Viewer zeigt die Änderung auf, die du in einem Text-Diff übersehen könntest.
  • NaN, Infinity und undefined sind keine JSON-Werte; beide Eingaben müssen RFC-8259-gültig sein. Entferne sie vor dem Einfügen.
  • Lange Zeichenfolgen mit eingebettetem JSON werden nicht entpackt. Wenn ein Feld eine JSON-Zeichenfolge speichert (ein häufiges API-Fehldesign), vergleicht der Viewer die vollständige zitierte Zeichenfolge und du siehst eine einzelne Ersetzen-Operation, keinen strukturellen Diff.
  • Leerzeichen innerhalb von Zeichenfolgenwerten ist bedeutsam. "hallo welt" und "hallo welt" (ein Leerzeichen vs. zwei) sind unterschiedliche Werte; dies ist JSON-korrekt, überrascht aber Entwickler, die an verlustbehaftete Diffs gewöhnt sind.
  • Der Viewer gibt keine RFC-6902-Patch-Dokumente direkt aus. Die Ausgabe ist strukturell ähnlich, verwendet aber freundlichere Operationsnamen; leite durch fast-json-patch, wenn du das kanonische Patch-Format benötigst.

JSON-Pointer (RFC 6901) und JSON-Patch (RFC 6902)

JSON-Pointer (RFC 6901, 2013) definiert eine einzeilige Zeichenfolgensyntax für die Benennung eines beliebigen Wertes in einem JSON-Dokument: eine Folge von schrägstrich-präfigierten Referenz-Tokens, bei denen ~ und / maskiert werden. JSON-Patch (RFC 6902) baut auf Pointer auf, um eine Liste von add-, remove-, replace-, move-, copy- und test-Operationen als JSON-Dokument selbst zu spezifizieren, das atomisch auf ein Zieldokument angewendet werden soll. Die Ausgabe des Diff-Viewers ist konzeptionell eine Teilmenge von RFC 6902: er gibt add-, remove- und replace-Operationen mit Pfaden aus, produziert aber nicht das formale Patch-Dokument. Das Verpacken der Operationsliste in [] und das Umbenennen der Arten ergibt ein gültiges Patch.

Alternativen und wann sie dieses Werkzeug übertreffen

Das CLI-Werkzeug jd (Go) erzeugt farbige Terminal-Ausgabe mit nativer YAML- und JSON-Unterstützung und ist die richtige Wahl für Stapelaufgaben. fast-json-patch auf npm berechnet RFC-6902-Patches programmatisch und ist das, was die meisten serverseitigen JS-Diffs verwenden. jsondiffpatch (npm) führt LCS-Stil-Array-Ausrichtung durch und gibt HTML-Diffs für menschliche Überprüfung aus. Pythons deepdiff (PyPI) ist das Äquivalent für Backends in dieser Sprache. Der seitengebundene Viewer gewinnt, wenn du zwei Payloads in der Zwischenablage hast, einen strukturierten Vergleich ohne Installation von Werkzeugketten möchtest und keine sensiblen Daten zu einem Fremddienst wie jsondiff.com hochladen willst.

Häufig gestellte Fragen

Wie unterscheidet sich das von einem Text-Diff?

Ein Text-Diff wie <code>diff -u</code> ist zeilenbewusst - das Neuanordnen von Schlüsseln oder das Umformatieren von Leerzeichen erzeugt laute falsch-positive Änderungen. Der JSON-Diff-Viewer parst beide Seiten und vergleicht Werte strukturell, sodass <code>{"a":1,"b":2}</code> und <code>{"b":2,"a":1}</code> als gleich gelten.

Welche Pfade verwendet der Viewer?

JSONPointer (RFC 6901). Jede Diff-Operation trägt einen Pfad wie <code>/user/name</code>, den du in <code>jq</code>, fast-json-patch oder jeden RFC-6901-Konsumenten einfügen kannst. <code>/</code> allein repräsentiert das Wurzeldokument.

Wie werden Arrays verglichen?

Element für Element nach Index in Dokumentenreihenfolge. Wenn die rechte Seite zusätzliche Elemente hat, erscheinen sie als <code>add</code>- Operationen; fehlende erscheinen als <code>remove</code>-Operationen am entsprechenden Index. Der Viewer versucht KEINE LCS-Ausrichtung - das Einfügen eines Elements am Anfang eines Arrays sieht daher wie eine Kette von Ersetzungen plus einem Hinzufügen aus, was die korrekte Semantik für indexbasierte Daten ist.

Lädt der Viewer mein JSON hoch?

Nein. Beide Dokumente werden in deinem Browser-Tab geparst und verglichen. Es gibt keinen fetch-Aufruf, keinen Analytics-Beacon für den Dokumentinhalt. Überprüfe es in den DevTools, indem du den Netzwerk-Tab öffnest und auf "Vergleichen" drückst.

Wie werden Objektschlüssel mit Schrägstrichen angezeigt?

JSONPointer maskiert <code>~</code> als <code>~0</code> und <code>/</code> als <code>~1</code>. Eine Änderung bei <code>{"a/b": 1}</code> -> <code>{"a/b": 2}</code> wird als Pfad <code>/a~1b</code> angezeigt, was die wörtliche RFC-6901-Form ist.

Was zählt als Ersetzen versus Hinzufügen plus Entfernen?

Wenn beide Seiten denselben Schlüssel (oder Array-Index) haben, aber unterschiedliche Werte, gibt der Viewer eine einzelne <code>replace</code>-Operation aus, die den alten und neuen Wert enthält. Ein <code>add</code> bedeutet, dass der Schlüssel nur auf der rechten Seite vorhanden ist; ein <code>remove</code> bedeutet, er ist nur auf der linken Seite. Ein in ein anderes übergeordnetes Element verschobener Schlüssel wird als Entfernen plus Hinzufügen angezeigt, da der Viewer keine Verschiebungen verfolgt.

Werden verschachtelte Objekte tief verglichen?

Ja. Der Komparator rekurriert in verschachtelte Objekte und Arrays, sodass eine Änderung drei Ebenen tief als eine Operation auf diesem tiefen Pfad erscheint, nicht als Ersetzen des übergeordneten Elements. Identische Unterobjekte mit neu geordneten Schlüsseln werden als gleich gemeldet, was der Kern eines semantischen Diffs ist.

Ist die Reihenfolge der beiden Dokumente relevant?

Sie bestimmt die Richtung. Das linke Fenster ist das Original, das rechte die geänderte Version, sodass das Tauschen jedes <code>add</code> in ein <code>remove</code> verwandelt und umgekehrt, während <code>replace</code>-Operationen alte und neue Werte vertauschen. Platziere die Baseline links, damit Diffs wie ein Änderungsprotokoll gelesen werden.

Kann ich zwei große JSON-Dateien im Browser vergleichen?

Komfortabel bis zu einigen Megabytes pro Seite. Beide Dokumente werden geparst und in einem einzigen Durchlauf traversiert, sodass der Tab gleichzeitig zwei Bäume plus die Operationsliste hält. Für sehr große Payloads sampele den relevanten Unterbaum oder verwende eine streaming CLI wie <code>jd</code> oder <code>jq</code>.

Wie wandle ich die Ausgabe in ein echtes JSON-Patch um?

Verpacke die Operationsliste in <code>[]</code>, benenne die Arten in die RFC-6902-Verben um (<code>add</code>, <code>remove</code>, <code>replace</code>) und behalte die Pfade unverändert. Für ein kanonisches Patch leite beide Dokumente durch <code>fast-json-patch</code> auf npm, das die genaue RFC-6902-Form ausgibt.

Mehr Developer Tools