Sådan sammenligner du to JSON-filer og finder hvad der er ændret

Den hurtigste måde at sammenligne to JSON-filer er at indsætte dem begge i et diff-værktøj side om side, formatere dem på samme måde og læse de linjer det fremhæver. Den svære del er normalt ikke selve sammenligningen. Det er støjen: omordnede nøgler, forskellig indrykning og løse afsluttende kommaer kan få to næsten identiske filer til at se ud som om de ikke deler noget som helst.

Denne guide gennemgår hvordan man får en ren og pålidelig diff. Vi ser på hvorfor JSON-filer drifter fra hinanden på papiret mens de forbliver ens i betydning, de få metoder der er værd at kende, og et gennemarbejdet eksempel du kan følge med i. Hvis du bare vil have værktøjet, gør vores JSON-sammenligningsside alt dette i browseren.

Hvorfor JSON-filer er bedragerisk svære at sammenligne

JSON har en lille, streng grammatik (se specifikationen på json.org), men giver forfattere stor frihed i hvordan de lægger teksten ud. To filer kan beskrive det nøjagtig samme objekt og alligevel adskille sig byte for byte. En almindelig tekstdiff ved intet af dette, så den flager trofast det hele.

Her er noget at internalisere inden du begynder: objektnøgler i JSON har ingen rækkefølge. Specifikationen (RFC 8259) definerer et objekt som et uordnet sæt af navn/værdi-par. Så {"name":"Ada","id":7} og {"id":7,"name":"Ada"} er ens, selvom en linjesdiff vil male dem røde og grønne.

Ligner en ændring, er det som regel ikke
Hvad du ser i diff'enEr det en reel ændring?Hvad du skal gøre
Nøgler i en anden rækkefølgeNej, objekter er uordnedeSorter nøgler på begge sider
2-mellemrum vs 4-mellemrum indrykningNejFormater begge sider ens
Minificeret vs pænt udskrevetNejFormater begge sider
Afsluttende linjeskift i slutningen af filenNejIgnorer, eller trim whitespace
En værdi ændret fra "7" til 7Ja, streng vs talUndersøg, dette er reelt
Array-elementer i en anden rækkefølgeMåske, arrays er ordnedeAfgør om rækkefølgen betyder noget her

Den sidste række overrasker folk. Arrays bevarer deres rækkefølge, objekter gør det ikke. Så [1, 2, 3] og [3, 2, 1] er genuint forskellige, men nøglerne inde i et objekt kan flyttes frit rundt. Hvis du vil have de tekniske detaljer om hvordan JavaScript parser alt dette, har MDN en solid reference om JSON-objektet.

Fire måder at sammenligne JSON på, og hvornår man bruger hvilken

Der er ingen enkelt bedste metode. Det afhænger af hvor filerne befinder sig og hvad du forsøger at lære. Sådan klarer de almindelige muligheder sig.

MetodeBedst tilIndsatsForstår JSON?
Se det igennemSmå filer, et eller to felterLavNej, du er parseren
Online diff-værktøjHurtige kontroller, indsætte fra alle stederLavMed format + sorter nøgler, ja
Kommandolinje (jq, diff)Filer på disk, scripting, store filerMellemJa, når du sorterer først
IDE eller git diffFiler allerede i et repoLav hvis committedLinjebaseret som standard

For de fleste mennesker vinder et browserværktøj på hastighed fordi der ikke er noget at installere og du kan indsætte et uddrag direkte fra en log eller et API-kald. Ulempen er formateringsstøj, som vi tager os af næste. Hvis du lever på terminalen er jq værktøjet at lære, og vi viser det ene flag der betyder noget.

Den hurtigste rene sammenligning, trin for trin

Dette er den rutine jeg bruger når nogen rækker mig to konfigurationsfiler og spørger "hvad er anderledes?". Det tager cirka femten sekunder.

  1. Åbn JSON-sammenligningsværktøjet.
  2. Indsæt originalen til venstre, den nye version til højre.
  3. Klik på Formater på begge sider så de deler den samme indrykning.
  4. Slå sorter nøgler (kanoniser) til så omordnede nøgler ikke længere vises som ændringer.
  5. Læs resultatet. Grønt er tilføjet, rødt er fjernet, og en ændret værdi vises som en af hver.

Trin tre og fire er hele tricket. Når begge filer er identisk formaterede og deres nøgler er sorterede, er det eneste der er tilbage at fremhæve hvad der faktisk er ændret. Vores diff-motor er bygget på Googles diff-match-patch, der sammenligner linje for linje først så den forbliver hurtig selv på lange filer.

Et gennemarbejdet eksempel

Lad os sige du gennemgår en ændring af en brugerpost. Her er tilstanden før:

{
  "name": "Ada Lovelace",
  "role": "editor",
  "active": true,
  "seats": 3
}

Og her er tilstanden efter, som en holdkammerat rakte dig den:

{
  "active": true,
  "name": "Ada Lovelace",
  "role": "admin",
  "seats": 5,
  "team": "platform"
}

Smid dem ind i en rå linjesdiff og det ligner at næsten alle linjer er rykket, fordi nøglerne er i en anden rækkefølge. Formater og sorter begge, og den rigtige historie er kort:

Hvad der faktisk er ændret
FeltFørEfterÆndring
roleeditoradminÆndret
seats35Ændret
teamplatformTilføjet
nameAda LovelaceAda LovelaceIngen ændring
activetruetrueIngen ændring (kun flyttet)

Tre reelle redigeringer: en rolleforfremmelse, et sædeantal og et nyt teamfelt. Omordningen var støj. Den forfremmelse fra editor til admin er præcis den slags ting du vil opfange i review, og den er nem at overse når den er begravet under tyve linjer falske positiver.

At eliminere formateringsstøj på kommandolinjen

Hvis dine filer allerede er på disk, fungerer den samme "formater og sorter" idé med to korte kommandoer. Flaget -S fortæller jq at sortere objektnøgler; at røre begge filer igennem det normaliserer dem så en almindelig diff er ærlig:

jq -S . old.json > old.sorted.json
jq -S . new.json > new.sorted.json
diff old.sorted.json new.sorted.json

Nu rapporterer diff kun værdier der virkelig er ændret, fordi begge filer har den samme indrykning og den samme nøglerækkefølge. Dette er terminalækvivalenten til at klikke Formater og sorter nøgler i browseren.

Tekstdiff vs strukturel diff

Alt ovenstående er en tekstdiff: hurtig, visuel og perfekt for et menneske der læser en ændring. En strukturel diff går videre og beskriver ændringen som data. Standarden for det er JSON Patch, defineret i RFC 6902, der udtrykker redigeringer som operationer som replace og add ved en given sti. Du vil have en strukturel diff når et program skal anvende ændringen, ikke bare en person der ser på den. Til daglig review er en tekstdiff med sorterede nøgler rigeligt.

Almindelige faldgruber at holde øje med

FaldgrubeHvorfor den biderLøsning
TalpræcisionHeltal over 2^53 − 1 mister præcision i JavaScriptSammenlign store ID'er som strenge; se MAX_SAFE_INTEGER
Unicode-escape"café" og "café" er den samme streng, forskellige bytesFormater begge sider, hvilket normaliserer kodningen
Duplikerede nøglerDe fleste parsere beholder stille den sidsteValider JSON'en inden du stoler på diff'en
Afsluttende kommaerIkke lovlig JSON; en fil kan måske slet ikke parsesRet syntaksen først, validatoren vil flage det
Streng vs tal"5" og 5 ligner hinanden men er forskellige typerDette er en reel ændring, afvis den ikke

Relaterede værktøjer

JSON er sjældent det eneste format du har med at gøre. Hvis du sammenligner konfiguration på tværs af miljøer anvender YAML-sammenligning den samme idé på YAML. At gennemgå ændringer mellem to API-kald er hvad API-responsdiff-værktøjet er bygget til, og afhængighedsopdateringer er nemmest at læse på package.json diff-siden.

Ofte stillede spørgsmål

Uploader sammenligning af JSON-filer online dem et sted?
På comparetext.org kører diff'en i din browser. De to JSON-filer sammenlignes af JavaScript på din egen maskine, så intet sendes til en server medmindre du eksplicit klikker Gem eller Del. Det gør det sikkert til konfigurationsfiler, API-svar og andre data du ikke ville ønske at indsætte på et tilfældig website der uploader ved hvert tastetryk.
Hvorfor viser mine to JSON-filer hver linje som anderledes?
Næsten altid er det formatering, ikke reelle ændringer. En fil er minificeret eller indrykket med tabs, den anden med to mellemrum, eller objektnøglerne er i en anden rækkefølge. Klik på Formater på begge sider så de bruger den samme indrykning, sorter derefter nøglerne så rækkefølge holder op med at betyde noget. Derefter krymper diff'en normalt til de få værdier der virkelig er ændret.
Hvordan sammenligner jeg JSON mens jeg ignorerer nøglerækkefølge?
JSON-objektnøgler har ingen defineret rækkefølge, så {"a":1,"b":2} og {"b":2,"a":1} er ens. For at få en tekstdiff til at være enig, sorter nøglerne på begge sider inden sammenligning. I browseren, brug kanoniser (sorter nøgler) indstillingen. På kommandolinjen gør jq det: jq -S . file.json. Når begge filer har nøgler i den samme sorterede rækkefølge, dukker kun reelle værdiændringer op.
Kan jeg sammenligne store JSON-filer uden at siden fryser?
Ja, op til et punkt. En linjesdiff forbliver hurtig på filer med tusindvis af linjer fordi den sammenligner hele linjer først i stedet for hvert tegn. Meget store filer (adskillige megabytes) håndteres bedre med et kommandolinjeværktøj som jq eller git diff, der streamer data. For alt du komfortabelt kan scrolle igennem i en browser er en online diff den hurtigere mulighed.
Hvad er forskellen mellem en tekstdiff og en strukturel diff af JSON?
En tekstdiff sammenligner filerne linje for linje, på samme måde som den ville sammenligne to essays. En strukturel diff forstår JSON, så den ved at en omordnet nøgle ikke er en ændring og at en værdi der er rykket inde i et array er et flyt, ikke en sletning plus en tilføjelse. Tekstdiff'er er hurtigere og gode nok til de fleste reviews. Strukturelle diff'er (for eksempel JSON Patch per RFC 6902) betyder noget når du skal beskrive en ændring som data et program kan anvende.
Hvordan sammenligner jeg to API-svar?
Gem hvert svar til en fil eller kopiér det fra din browsers netværksfane, indsæt derefter det gamle svar til venstre og det nye til højre. Formater begge så indrykning matcher, og sorter nøgler hvis API'et ikke returnerer dem i en stabil rækkefølge. Værktøjet api-response-diff er afstemt til præcis dette: at spotte et omdøbt felt, en ændret statuskode, eller en værdi der flippede fra en streng til et tal mellem to kald.

Klar til at prøve det? Indsæt dine filer i JSON-sammenligningsværktøjet og se hvad der er ændret.