Porównaj dwie struktury JSON
- Panel
- Dokumentacja
- API
Dlaczego porównywać dwa JSON-y?
Porównywanie dwóch struktur JSON regularnie zdarza się w życiu programisty. Odpowiedź API, która zmienia się po aktualizacji. Plik konfiguracyjny rozbieżny między dwoma środowiskami. Eksport obiektów, który musi być zgodny z referencją. Diff JSON odpowiada dokładnie na to pytanie: co zostało dodane, usunięte lub zmodyfikowane i w którym miejscu?
Diff linia po linii (w stylu git diff) często nie wystarcza. Jeśli różni się
formatowanie (spacje, kolejność kluczy), tekstowy diff sygnalizuje setki linii, podczas gdy struktura
danych jest identyczna. Komparator JSON pracuje na strukturze po sparsowaniu, co eliminuje ten szum
i ujawnia tylko semantyczne różnice.
Format diffu produkowanego przez narzędzie
Dla każdej różnicy narzędzie zwraca:
- ścieżkę w uproszczonym formacie JSONPath, na przykład
$.user.address[0].city; - typ spośród added (dodano po prawej), removed (obecne tylko po lewej), modified (różne wartości);
- wartość po lewej i/lub wartość po prawej w zależności od typu.
Pusty diff oznacza, że oba JSON-y są strukturalnie identyczne, niezależnie od ich formatowania lub kolejności kluczy.
Jak algorytm przeszukuje dwie struktury
Algorytm jest rekurencyjny. Na każdym poziomie identyfikuje typ dwóch porównywanych wartości:
- Jeśli oba są obiektami asocjacyjnymi, bierze sumę kluczy. Dla każdego klucza schodzi rekurencyjnie lub oznacza added/removed, jeśli klucz istnieje tylko po jednej stronie.
- Jeśli oba są uporządkowanymi tablicami, porównuje pozycja po pozycji. Różnica na początku tablicy może przesunąć całą resztę, co produkuje gadatliwy diff: to znane ograniczenie naiwnego diffu strukturalnego.
- Jeśli typy się różnią (obiekt vs tablica, skalar vs null), jest to oznaczone modified.
- Jeśli obie wartości są skalarami (ciąg, liczba, boolean, null), wystarczy proste ścisłe porównanie.
Kolejność kluczy w obiekcie nie ma znaczenia: {"a": 1, "b": 2} i {"b": 2, "a": 1}
produkują pusty diff. Jest to zgodne z semantyką JSON, gdzie kolejność nie jest znacząca. Natomiast
kolejność elementów tablicy ma znaczenie: tablica jest z założenia uporządkowana.
Konkretny przykład
Oto dwie wersje obiektu użytkownika:
// gauche
{
"id": 42,
"name": "Alice",
"roles": ["admin", "editor"]
}
// droite
{
"id": 42,
"name": "Alice Martin",
"roles": ["admin", "viewer"],
"active": true
}
Wyprodukowany diff:
$.name: modified,"Alice"→"Alice Martin"$.roles[1]: modified,"editor"→"viewer"$.active: added,true
Przypadki użycia
- Diff środowisk: porównanie wyjścia endpointu w preprodukcji i w produkcji. Bardzo przydatne podczas migracji lub odświeżania cache.
- Audyt migracji: porównanie eksportu przed i po transformacji, aby zweryfikować, że żadne pole nie zostało utracone.
- Regresja API: przed i po modyfikacji porównanie odpowiedzi dla identycznego zapytania. Pusty diff potwierdza brak regresji.
- Synchronizacja konfiguracji: porównanie
composer.jsonmiędzy dwoma gałęziami, dwóch plików.eslintrc, dwóch konfiguracji Symfony. - Snapshot tests: zastąpienie porównania linia po linii porównaniem strukturalnym w zestawie testów integracyjnych.
Ograniczenia diffu strukturalnego
Porównywanie uporządkowanych tablic to znane ograniczenie naiwnych diffów strukturalnych. Wstawienie elementu na początku tablicy przesuwa wszystkie kolejne pozycje, a diff sygnalizuje każdą różnicę jako modyfikację. Dla takich przypadków istnieją bardziej zaawansowane algorytmy (Myers, Patience, diff według naturalnego klucza), ale wykraczają poza zakres uniwersalnego narzędzia porównawczego.
Diff nie mówi też, dlaczego doszło do zmiany: to obserwacja. Aby przeanalizować regresję, trzeba skrzyżować to z commitami, wdrożeniami i parametrami żądania.
JSON diff vs JSON Patch (RFC 6902)
Uzupełniającym formatem jest JSON Patch (RFC 6902). Opisuje on, w formie operacji
(add, remove, replace, move, copy,
test), jak przekształcić dokument JSON w inny. Tam gdzie nasz diff to obserwacja
(ludzka), JSON Patch to przepis (maszynowy). Obie reprezentacje są równoważne dla prostych
przypadków, a JSON Patch jest przydatny dla API RESTful, które akceptują częściowe modyfikacje.
Najczęściej zadawane pytania
Czy diff zależy od kolejności kluczy?
Nie: dla obiektu JSON kolejność nie jest znacząca. Komparator produkuje ten sam wynik, niezależnie od tego, czy klucze są posortowane czy nie.
Jak obsługiwać tablice, których kolejność nie ma znaczenia?
Narzędzie domyślnie traktuje tablice jako uporządkowane (taka jest semantyka JSON). Jeśli przetwarzasz zbiory, posortuj obie tablice według naturalnego klucza przed porównaniem lub użyj wyspecjalizowanej usługi porównawczej, która uwzględnia tę semantykę.
Jaka jest różnica w stosunku do diffu Git?
Git porównuje linie tekstu. Jeśli wcięcie lub kolejność kluczy różni się, diff Git jest bardzo gadatliwy. Diff JSON pracuje na sparsowanej strukturze i sygnalizuje tylko różnice danych.
Czy nieprawidłowy JSON jest akceptowany?
Nie: jeśli jeden z dwóch JSON-ów się nie parsuje, narzędzie zwraca błąd. Najpierw zweryfikuj go naszym walidatorem JSON.
Przykładowe zapytanie
curl -X POST https://cdrn.fr/api/v1/tools/json-diff/execute \
-H "Content-Type: application/json" \
-d '{"left":"...","right":"..."}'
Schemat wejściowy
| Pole | Typ | Wymagane | Domyślnie |
|---|---|---|---|
left |
text | ✓ | – |
right |
text | ✓ | – |
Punkty końcowe
GET https://cdrn.fr/api/v1/tools- lista wszystkich dostępnych narzędziGET https://cdrn.fr/api/v1/tools/json-diff- zwraca schemat dla tego narzędziaPOST https://cdrn.fr/api/v1/tools/json-diff/execute- uruchamia to narzędzie z payloadem JSON