Hvordan sammenligne to JSON-filer og finne hva som har endret seg

Den raskeste måten å sammenligne to JSON-filer er å lime inn begge i et diff-verktøy side om side, formatere dem på samme måte og lese linjene det fremhever. Den vanskelige delen er vanligvis ikke selve sammenligningen. Det er støyen: omordnede nøkler, ulik innrykking og løse avsluttende kommaer kan få to nesten identiske filer til å se ut som om de ikke deler noe som helst.

Denne guiden går gjennom hvordan man får en ren og pålitelig diff. Vi ser på hvorfor JSON-filer drifter fra hverandre på papiret mens de forblir like i betydning, de få metodene som er verdt å kjenne til, og et gjennomarbeidet eksempel du kan følge med på. Hvis du bare vil ha verktøyet, gjør vår JSON-sammenligningsside alt dette i nettleseren.

Hvorfor JSON-filer er bedragerisk vanskelige å sammenligne

JSON har en liten, streng grammatikk (se spesifikasjonen på json.org), men gir forfattere stor frihet i hvordan de legger ut teksten. To filer kan beskrive nøyaktig det samme objektet og likevel skille seg byte for byte. En vanlig tekstdiff vet ikke noe av dette, så den flaggere trofast alt.

Her er noe å internalisere før du begynner: objektnøkler i JSON har ingen rekkefølge. Spesifikasjonen (RFC 8259) definerer et objekt som et uordnet sett av navn/verdi-par. Så {"name":"Ada","id":7} og {"id":7,"name":"Ada"} er like, selv om en linjediff vil male dem røde og grønne.

Ser ut som en endring, er det som regel ikke
Hva du ser i diff'enEr det en reell endring?Hva du skal gjøre
Nøkler i annen rekkefølgeNei, objekter er uordnedeSorter nøkler på begge sider
2-mellomrom vs 4-mellomrom innrykkingNeiFormater begge sider likt
Minifisert vs pent utskrevetNeiFormater begge sider
Avsluttende linjeskift på slutten av filenNeiIgnorer, eller trim mellomrom
En verdi endret fra "7" til 7Ja, streng vs tallUndersøk, dette er reelt
Array-elementer i annen rekkefølgeKanskje, arrays er ordnedeAvgjør om rekkefølgen har betydning her

Den siste raden overrasker folk. Arrays beholder rekkefølgen sin, objekter gjør ikke det. Så [1, 2, 3] og [3, 2, 1] er genuint forskjellige, men nøklene innenfor et objekt kan stokkes fritt. Hvis du vil ha de tekniske detaljene om hvordan JavaScript parser alt dette, har MDN en solid referanse om JSON-objektet.

Fire måter å sammenligne JSON på, og når man bruker hvilken

Det finnes ingen enkelt beste metode. Det avhenger av hvor filene befinner seg og hva du prøver å lære. Slik stiller de vanlige alternativene seg opp.

MetodeBest tilInnsatsForstår JSON?
Se det gjennomSmå filer, ett eller to felterLavNei, du er parseren
Online diff-verktøyRaske sjekker, lime inn fra overaltLavMed format + sorter nøkler, ja
Kommandolinje (jq, diff)Filer på disk, skripting, store filerMiddelsJa, når du sorterer først
IDE eller git diffFiler allerede i et repoLav hvis committedLinjebasert som standard

For de fleste vinner et nettleserverktøy på hastighet fordi det ikke er noe å installere og du kan lime inn et utdrag rett fra en logg eller et API-kall. Ulempen er formateringsstøy, som vi tar oss av neste. Hvis du lever på terminalen er jq verktøyet å lære, og vi viser det ene flagget som betyr noe.

Den raskeste rene sammenligningen, steg for steg

Dette er rutinen jeg bruker når noen rekker meg to konfigurasjonsfiler og spør "hva er annerledes?". Det tar omtrent femten sekunder.

  1. Åpne JSON-sammenligningsverktøyet.
  2. Lim inn originalen til venstre, den nye versjonen til høyre.
  3. Klikk på Formater på begge sider slik at de deler den samme innrykkingen.
  4. Slå på sorter nøkler (kanoniser) slik at omordnede nøkler slutter å vises som endringer.
  5. Les resultatet. Grønt er lagt til, rødt er fjernet, og en endret verdi vises som ett av hvert.

Steg tre og fire er hele trikset. Når begge filene er identisk formatert og nøklene er sortert, er det eneste som er igjen å fremheve det som faktisk har endret seg. Diff-motoren vår er bygget på Googles diff-match-patch, som sammenligner linje for linje først slik at den forblir rask selv på lange filer.

Et gjennomarbeidet eksempel

Si at du gjennomgår en endring i en brukerpost. Her er tilstanden før:

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

Og her er tilstanden etter, slik en lagkamerat ga den til deg:

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

Legg dem inn i en rå linjediff og det ser ut som at nesten alle linjer har flyttet seg, fordi nøklene er i en annen rekkefølge. Formater og sorter begge, og den sanne historien er kort:

Hva som faktisk har endret seg
FeltFørEtterEndring
roleeditoradminEndret
seats35Endret
teamplatformLagt til
nameAda LovelaceAda LovelaceIngen endring
activetruetrueIngen endring (bare flyttet)

Tre reelle redigeringer: en rolleoppgradering, et setesantall og et nytt teamfelt. Omordningen var støy. Den forfremmelsen fra editor til admin er akkurat den typen ting du vil fange opp i en gjennomgang, og den er lett å overse når den er begravet under tjue linjer falske positiver.

Å eliminere formateringsstøy på kommandolinjen

Hvis filene dine allerede er på disk, fungerer den samme "formater og sorter"-ideen med to korte kommandoer. Flagget -S forteller jq å sortere objektnøkler; å røre begge filene gjennom det normaliserer dem slik at en vanlig diff er ærlig:

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

Nå rapporterer diff bare verdier som virkelig har endret seg, fordi begge filene har den samme innrykkingen og den samme nøkkelrekkefølgen. Dette er terminalmotstykkeet til å klikke Formater og sorter nøkler i nettleseren.

Tekstdiff vs strukturell diff

Alt ovenfor er en tekstdiff: rask, visuell og perfekt for et menneske som leser en endring. En strukturell diff går lenger og beskriver endringen som data. Standarden for det er JSON Patch, definert i RFC 6902, som uttrykker redigeringer som operasjoner som replace og add ved en gitt sti. Du vil ha en strukturell diff når et program trenger å anvende endringen, ikke bare en person som ser på den. Til daglig gjennomgang er en tekstdiff med sorterte nøkler mer enn nok.

Vanlige fallgruver å se opp for

FallgruveHvorfor den biterLøsning
TallpresisjonHeltall over 2^53 − 1 mister presisjon i JavaScriptSammenlign store ID-er som strenger; se MAX_SAFE_INTEGER
Unicode-escape"café" og "café" er den samme strengen, forskjellige bytesFormater begge sider, noe som normaliserer kodingen
Dupliserte nøklerDe fleste parsere beholder stille den sisteValider JSON-en før du stoler på diff'en
Avsluttende kommaerIkke lovlig JSON; en fil kan kanskje ikke engang parsesFiks syntaksen først, validatoren vil flagge det
Streng vs tall"5" og 5 ser like ut men er forskjellige typerDette er en reell endring, ikke avvis den

Relaterte verktøy

JSON er sjelden det eneste formatet du har med å gjøre. Hvis du sammenligner konfigurasjon på tvers av miljøer, bruker YAML-sammenligning den samme ideen på YAML. Å gjennomgå endringer mellom to API-kall er hva API-responsdiff-verktøyet er bygget for, og avhengighetsoppdateringer er enklest å lese på package.json diff-siden.

Ofte stilte spørsmål

Laster sammenligning av JSON-filer online dem opp et sted?
På comparetext.org kjører diff'en i nettleseren din. De to JSON-filene sammenlignes av JavaScript på din egen maskin, så ingenting sendes til en server med mindre du eksplisitt klikker Lagre eller Del. Det gjør det trygt for konfigurasjonsfiler, API-svar og andre data du ikke ville ønske å lime inn på en tilfeldig nettside som laster opp ved hvert tastetrykk.
Hvorfor viser mine to JSON-filer hver linje som annerledes?
Nesten alltid er det formatering, ikke reelle endringer. En fil er minifisert eller rykket inn med tabulator, den andre med to mellomrom, eller objektnøklene er i en annen rekkefølge. Klikk Formater på begge sider slik at de bruker den samme innrykkingen, sorter deretter nøklene slik at rekkefølge slutter å ha betydning. Etter det krymper diff'en vanligvis til de få verdiene som genuint har endret seg.
Hvordan sammenligner jeg JSON mens jeg ignorerer nøkkelrekkefølge?
JSON-objektnøkler har ingen definert rekkefølge, så {"a":1,"b":2} og {"b":2,"a":1} er like. For å få en tekstdiff til å være enig, sorter nøklene på begge sider før sammenligning. I nettleseren, bruk kanoniser (sorter nøkler) alternativet. På kommandolinjen gjør jq det: jq -S . file.json. Når begge filene har nøkler i den samme sorterte rekkefølgen, dukker bare reelle verdiendringer opp.
Kan jeg sammenligne store JSON-filer uten at siden fryser?
Ja, opp til et punkt. En linjediff forblir rask på filer med tusenvis av linjer fordi den sammenligner hele linjer først i stedet for hvert tegn. Svært store filer (flere megabytes) håndteres bedre med et kommandolinjeverktøy som jq eller git diff, som strømmer data. For alt du komfortabelt kan rulle gjennom i en nettleser, er en online diff det raskere alternativet.
Hva er forskjellen mellom en tekstdiff og en strukturell diff av JSON?
En tekstdiff sammenligner filene linje for linje, på samme måte som den ville sammenligne to essays. En strukturell diff forstår JSON, så den vet at en omordnet nøkkel ikke er en endring og at en verdi som er flyttet inne i en array er et flytt, ikke en sletting pluss en tillegging. Tekstdiff-er er raskere og gode nok for de fleste gjennomganger. Strukturelle diff-er (for eksempel JSON Patch per RFC 6902) betyr noe når du trenger å beskrive en endring som data et program kan anvende.
Hvordan sammenligner jeg to API-svar?
Lagre hvert svar til en fil eller kopier det fra nettleserens nettverksfane, lim deretter inn det gamle svaret til venstre og det nye til høyre. Formater begge slik at innrykkingen stemmer, og sorter nøkler hvis API-et ikke returnerer dem i en stabil rekkefølge. Verktøyet api-response-diff er stilt inn for akkurat dette: å oppdage et omdøpt felt, en endret statuskode, eller en verdi som skiftet fra en streng til et tall mellom to kall.

Klar til å prøve det? Lim inn filene dine i JSON-sammenligningsverktøyet og se hva som har endret seg.