Jak porównać dwa pliki JSON i znaleźć zmiany
Najszybszym sposobem na porównanie dwóch plików JSON jest wklejenie obu do narzędzia diff z widokiem obok siebie, sformatowanie ich w ten sam sposób i odczytanie podświetlonych linii. Trudną częścią zwykle nie jest samo porównywanie. To szum: zmieniona kolejność kluczy, różne wcięcia i zbędne końcowe przecinki mogą sprawić, że dwa prawie identyczne pliki wyglądają, jakby nie miały nic wspólnego.
Ten przewodnik opisuje, jak uzyskać czysty i wiarygodny diff. Przyjrzymy się, dlaczego pliki JSON rozchodzą się na papierze, pozostając takie same w znaczeniu, kilku metodom wartym poznania oraz przepracowanemu przykładowi, który możesz śledzić. Jeśli potrzebujesz tylko narzędzia, nasza strona porównania JSON robi to wszystko w przeglądarce.
Dlaczego porównywanie plików JSON jest zwodniczo trudne
JSON ma małą, ścisłą gramatykę (zob. specyfikację na json.org), ale daje autorom dużą swobodę w układaniu tekstu. Dwa pliki mogą opisywać dokładnie ten sam obiekt i nadal różnić się bajt po bajcie. Zwykły diff tekstowy nic o tym nie wie, więc skrupulatnie oznacza wszystko.
Oto rzecz, którą należy przyswoić przed rozpoczęciem: klucze obiektów
w JSON nie mają kolejności. Specyfikacja
(RFC 8259)
definiuje obiekt jako nieuporządkowany zbiór par nazwa/wartość. Zatem
{"name":"Ada","id":7} i {"id":7,"name":"Ada"}
są równe, choć diff liniowy pokoloruje je na czerwono i zielono.
| Co widzisz w diffie | Czy to prawdziwa zmiana? | Co zrobić |
|---|---|---|
| Klucze w innej kolejności | Nie, obiekty są nieuporządkowane | Posortuj klucze po obu stronach |
| Wcięcie 2 vs 4 spacje | Nie | Sformatuj obie strony tak samo |
| Skrócony vs ładnie sformatowany | Nie | Sformatuj obie strony |
| Końcowy znak nowej linii na końcu pliku | Nie | Zignoruj lub przytnij białe znaki |
Wartość zmieniona z "7" na 7 | Tak, ciąg vs liczba | Zbadaj, to jest prawdziwe |
| Elementy tablicy w innej kolejności | Może, tablice są uporządkowane | Zdecyduj, czy kolejność ma tu znaczenie |
Ten ostatni wiersz zaskakuje ludzi. Tablice zachowują kolejność, obiekty
nie. Dlatego [1, 2, 3] i [3, 2, 1] są naprawdę
różne, ale klucze wewnątrz obiektu mogą się dowolnie przestawiać. Jeśli
chcesz poznać szczegóły dotyczące tego, jak JavaScript to wszystko
przetwarza, MDN ma solidny
opis obiektu JSON.
Cztery sposoby porównywania JSON i kiedy po który sięgać
Nie ma jednej najlepszej metody. Zależy od tego, gdzie znajdują się pliki i czego chcesz się dowiedzieć. Oto zestawienie popularnych opcji.
| Metoda | Najlepsza do | Wysiłek | Rozumie JSON? |
|---|---|---|---|
| Przeglądanie wzrokiem | Małe pliki, jedno lub dwa pola | Niski | Nie, parserem jesteś ty |
| Narzędzie diff online | Szybkie sprawdzenia, wklejanie skądkolwiek | Niski | Z formatem + sortowaniem kluczy, tak |
Wiersz poleceń (jq, diff) | Pliki na dysku, skryptowanie, duże pliki | Średni | Tak, gdy najpierw posortowane |
IDE lub git diff | Pliki już w repozytorium | Niski, jeśli zacommitowane | Liniowy domyślnie |
Dla większości osób narzędzie przeglądarkowe wygrywa szybkością, bo nie trzeba nic instalować i można wkleić fragment prosto z logu lub wywołania API. Problemem jest szum formatowania, którym zajmiemy się dalej. Jeśli żyjesz w terminalu, jq to narzędzie do opanowania i pokażemy jedną flagę, która ma znaczenie.
Najszybsze czyste porównanie krok po kroku
To rutyna, której używam, gdy ktoś podaje mi dwa pliki konfiguracyjne i pyta „co się różni?". Zajmuje około piętnastu sekund.
- Otwórz narzędzie do porównywania JSON.
- Wklej oryginał po lewej, nową wersję po prawej.
- Kliknij Formatuj po obu stronach, żeby używały tego samego wcięcia.
- Włącz sortowanie kluczy (kanonizuj), żeby zmieniona kolejność kluczy przestała być wyświetlana jako zmiana.
- Odczytaj wynik. Zielony oznacza dodane, czerwony usunięte, a zmieniona wartość jest pokazana jako jedno i drugie.
Kroki trzeci i czwarty to cały trik. Gdy oba pliki są identycznie sformatowane i ich klucze posortowane, jedyne, co pozostaje do podświetlenia, to to, co naprawdę się zmieniło. Nasz silnik diff jest zbudowany na bazie Google'owego diff-match-patch, który porównuje najpierw linia po linii, dzięki czemu pozostaje szybki nawet na długich plikach.
Przepracowany przykład
Powiedzmy, że przeglądasz zmianę w rekordzie użytkownika. Oto stan przed:
{
"name": "Ada Lovelace",
"role": "editor",
"active": true,
"seats": 3
}
A oto stan po, tak jak przekazał ci go kolega z zespołu:
{
"active": true,
"name": "Ada Lovelace",
"role": "admin",
"seats": 5,
"team": "platform"
}
Wrzuć je do surowego diffu liniowego, a wygląda, jakby prawie każda linia się przesunęła, bo klucze są w innej kolejności. Sformatuj i posortuj oba, a prawdziwa historia jest krótka:
| Pole | Przed | Po | Zmiana |
|---|---|---|---|
role | editor | admin | Zmieniono |
seats | 3 | 5 | Zmieniono |
team | — | platform | Dodano |
name | Ada Lovelace | Ada Lovelace | Bez zmian |
active | true | true | Bez zmian (tylko przesunięte) |
Trzy prawdziwe edycje: awans roli, liczba miejsc i nowe pole zespołu.
Zmiana kolejności to był szum. Ta promocja z editor do
admin to właśnie coś, co chcesz wychwycić podczas przeglądu,
i łatwo to przeoczyć, gdy jest zagrzebane pod dwudziestoma liniami
fałszywych alarmów.
Eliminowanie szumu formatowania w wierszu poleceń
Jeśli twoje pliki są już na dysku, ta sama idea „formatuj i sortuj" działa
za pomocą dwóch krótkich poleceń. Flaga -S mówi jq, żeby
sortował klucze obiektów; przepuszczenie przez nią obu plików normalizuje
je tak, że zwykły diff jest uczciwy:
jq -S . old.json > old.sorted.json
jq -S . new.json > new.sorted.json
diff old.sorted.json new.sorted.json
Teraz diff raportuje tylko wartości, które naprawdę się
zmieniły, ponieważ oba pliki mają to samo wcięcie i tę samą kolejność
kluczy. To odpowiednik kliknięcia Formatuj i sortuj klucze w przeglądarce.
Diff tekstowy a diff strukturalny
Wszystko powyżej to diff tekstowy: szybki, wizualny i doskonały
dla osoby czytającej zmianę. Diff strukturalny idzie dalej
i opisuje zmianę jako dane. Standardem jest JSON Patch, zdefiniowany
w
RFC 6902,
który wyraża edycje jako operacje takie jak replace
i add na danej ścieżce. Diffu strukturalnego potrzebujesz,
gdy program ma zastosować zmianę, a nie tylko osoba na nią patrząca.
Na co dzień diff tekstowy z posortowanymi kluczami w zupełności wystarcza.
Częste pułapki, na które należy uważać
| Pułapka | Dlaczego gryzie | Rozwiązanie |
|---|---|---|
| Precyzja liczb | Liczby całkowite powyżej 2^53 − 1 tracą precyzję w JavaScript | Porównuj duże ID jako ciągi; zob. MAX_SAFE_INTEGER |
| Sekwencje ucieczki Unicode | "café" i "café" to ten sam ciąg, różne bajty | Sformatuj obie strony, co normalizuje kodowanie |
| Zduplikowane klucze | Większość parserów cicho zachowuje ostatni | Zwaliduj JSON przed zaufaniem diffowi |
| Końcowe przecinki | Nie są legalnym JSON; jeden plik może w ogóle nie zostać sparsowany | Najpierw napraw składnię, walidator to oznaczy |
| Ciąg vs liczba | "5" i 5 wyglądają podobnie, ale są różnych typów | To jest prawdziwa zmiana, nie ignoruj jej |
Powiązane narzędzia
JSON rzadko jest jedynym formatem, z którym masz do czynienia. Jeśli porównujesz konfigurację między środowiskami, porównywanie YAML stosuje tę samą ideę do YAML. Przeglądanie zmian między dwoma wywołaniami API to zadanie, do którego stworzono narzędzie do diffowania odpowiedzi API, a aktualizacje zależności najłatwiej odczytać na stronie diff package.json.
Często zadawane pytania
- Czy porównywanie plików JSON online gdzieś je przesyła?
- Na comparetext.org diff działa w twojej przeglądarce. Dwa pliki JSON są porównywane przez JavaScript na twoim własnym komputerze, więc nic nie jest wysyłane na serwer, chyba że jawnie klikniesz Zapisz lub Udostępnij. To sprawia, że jest bezpieczne dla plików konfiguracyjnych, odpowiedzi API i innych danych, których nie chciałbyś wklejać na przypadkową stronę, która przesyła dane przy każdym naciśnięciu klawisza.
- Dlaczego moje dwa pliki JSON pokazują każdą linię jako różną?
- Prawie zawsze to formatowanie, nie prawdziwe zmiany. Jeden plik jest skrócony lub wcięty tabulatorami, drugi dwiema spacjami, albo klucze obiektów są w innej kolejności. Kliknij Formatuj po obu stronach, żeby używały tego samego wcięcia, a następnie posortuj klucze, żeby kolejność przestała mieć znaczenie. Po tym diff zwykle kurczy się do garści wartości, które naprawdę się zmieniły.
- Jak porównać JSON ignorując kolejność kluczy?
- Klucze obiektów JSON nie mają zdefiniowanej kolejności, więc
{"a":1,"b":2}i{"b":2,"a":1}są równe. Żeby diff tekstowy się z tym zgodził, posortuj klucze po obu stronach przed porównaniem. W przeglądarce użyj opcji kanonizuj (sortuj klucze). W wierszu poleceń robi to jq:jq -S . file.json. Gdy oba pliki mają klucze w tej samej posortowanej kolejności, widoczne są tylko prawdziwe zmiany wartości. - Czy mogę porównywać duże pliki JSON bez zamrażania strony?
- Tak, do pewnego stopnia. Diff liniowy pozostaje szybki na plikach z tysiącami linii, bo porównuje najpierw całe linie zamiast każdego znaku. Bardzo duże pliki (kilka megabajtów) lepiej obsługiwać narzędziem wiersza poleceń, jak jq lub git diff, które strumieniują dane. Dla wszystkiego, przez co możesz wygodnie przewijać w przeglądarce, diff online jest szybszą opcją.
- Jaka jest różnica między diffem tekstowym a strukturalnym JSON?
- Diff tekstowy porównuje pliki linia po linii, tak jak porównywałby dwa eseje. Diff strukturalny rozumie JSON, więc wie, że zmieniona kolejność klucza nie jest zmianą i że wartość przesunięta wewnątrz tablicy to przesunięcie, a nie usunięcie plus dodanie. Diffy tekstowe są szybsze i wystarczające dla większości przeglądów. Diffy strukturalne (np. JSON Patch według RFC 6902) mają znaczenie, gdy trzeba opisać zmianę jako dane, które program może zastosować.
- Jak porównać dwie odpowiedzi API?
- Zapisz każdą odpowiedź do pliku lub skopiuj ją z zakładki sieci w przeglądarce, następnie wklej starą odpowiedź po lewej, a nową po prawej. Sformatuj obie, żeby wcięcia się zgadzały, i posortuj klucze, jeśli API nie zwraca ich w stabilnej kolejności. Narzędzie api-response-diff jest dokładnie do tego dostrojone: wychwytywanie zmienionej nazwy pola, zmienionego kodu statusu lub wartości, która zmieniła się z ciągu na liczbę między dwoma wywołaniami.
Chcesz spróbować? Wklej swoje pliki do narzędzia do porównywania JSON i sprawdź, co się zmieniło.