Hur man jämför två JSON-filer och hittar vad som har ändrats

Det snabbaste sättet att jämföra två JSON-filer är att klistra in båda i ett diff-verktyg med sida-vid-sida-vy, formatera dem på samma sätt och läsa raderna det markerar. Den svåra delen är vanligtvis inte jämförelsen. Det är bruset: omordnade nycklar, olika indragningar och löst hängande avslutande kommatecken kan få två nästan identiska filer att se ut som om de inte delar något alls.

Den här guiden går igenom hur man får en ren och tillförlitlig diff. Vi tittar på varför JSON-filer driftar ifrån varandra på pappret medan de förblir likadana i betydelse, de få metoder som är värda att känna till, och ett genomarbetat exempel du kan följa med i. Om du bara vill ha verktyget gör vår JSON-jämförelsesida allt detta i webbläsaren.

Varför JSON-filer är bedrägligt svåra att jämföra

JSON har en liten, strikt grammatik (se specifikationen på json.org), men ger skribenter stor frihet i hur de lägger upp texten. Två filer kan beskriva exakt samma objekt och ändå skilja sig byte för byte. En vanlig textdiff vet inget av detta, så den flaggar troget allt.

Det här är något att ta till sig innan du börjar: objektnycklar i JSON har ingen ordning. Specifikationen (RFC 8259) definierar ett objekt som en oordnad mängd namn/värde-par. Så {"name":"Ada","id":7} och {"id":7,"name":"Ada"} är lika, även om en raddiff målar dem röda och gröna.

Ser ut som en förändring, är det vanligtvis inte
Vad du ser i diff:enÄr det en verklig förändring?Vad du ska göra
Nycklar i annan ordningNej, objekt är oordnadeSortera nycklar på båda sidor
2-mellanslag vs 4-mellanslag indragningNejFormatera båda sidor likadant
Minifierad vs snyggt utskrivenNejFormatera båda sidor
Avslutande radbrytning i slutet av filenNejIgnorera, eller trimma blanksteg
Ett värde ändrat från "7" till 7Ja, sträng vs nummerUndersök, detta är verkligt
Arrayelement i annan ordningKanske, arrayer är ordnadeBestäm om ordningen spelar roll här

Den sista raden överraskar folk. Arrayer behåller sin ordning, objekt gör det inte. Så [1, 2, 3] och [3, 2, 1] är genuint olika, men nycklarna inuti ett objekt kan blandas fritt. Om du vill ha de tekniska detaljerna om hur JavaScript parsar allt detta har MDN en solid referens om JSON-objektet.

Fyra sätt att jämföra JSON, och när man ska använda vilket

Det finns ingen enda bästa metod. Det beror på var filerna finns och vad du försöker ta reda på. Så här ställer sig de vanliga alternativen mot varandra.

MetodBäst förAnsträngningFörstår JSON?
Ögna igenomSmå filer, ett eller två fältLågNej, du är parsern
Online diff-verktygSnabba kontroller, klistra in varifrån som helstLågMed format + sortera nycklar, ja
Kommandorad (jq, diff)Filer på disk, skriptning, stora filerMedelJa, när du sorterar först
IDE eller git diffFiler redan i ett repoLåg om committadeRadbaserad som standard

För de flesta vinner ett webbläsarverktyg på hastighet eftersom det inte finns något att installera och du kan klistra in ett utdrag direkt från en logg eller ett API-anrop. Nackdelen är formateringsbrus, vilket vi tar itu med härnäst. Om du lever i terminalen är jq verktyget att lära sig, och vi visar den enda flaggan som spelar roll.

Den snabbaste rena jämförelsen, steg för steg

Det här är rutinen jag använder när någon räcker mig två konfigurationsfiler och frågar "vad är annorlunda?". Det tar ungefär femton sekunder.

  1. Öppna JSON-jämförelseverktyget.
  2. Klistra in originalet till vänster, den nya versionen till höger.
  3. Klicka på Formatera på båda sidor så att de delar samma indragning.
  4. Slå på sortera nycklar (kanonisera) så att omordnade nycklar slutar visas som ändringar.
  5. Läs resultatet. Grönt är tillagt, rött är borttaget, och ett ändrat värde visas som ett av vardera.

Steg tre och fyra är hela tricket. När båda filerna är identiskt formaterade och deras nycklar är sorterade är det enda kvar att markera det som faktiskt ändrades. Vår diff-motor är byggd på Googles diff-match-patch, som jämför rad för rad först så att den förblir snabb även på långa filer.

Ett genomarbetat exempel

Säg att du granskar en ändring i en användarpost. Här är tillståndet före:

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

Och här är tillståndet efter, som en lagkamrat lämnade över det till dig:

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

Lägg in dem i en rå raddiff och det ser ut som om nästan varje rad har flyttats, eftersom nycklarna är i en annan ordning. Formatera och sortera båda, och den verkliga historien är kort:

Vad som faktiskt ändrades
FältFöreEfterFörändring
roleeditoradminÄndrad
seats35Ändrad
teamplatformTillagd
nameAda LovelaceAda LovelaceIngen ändring
activetruetrueIngen ändring (bara omflyttad)

Tre verkliga redigeringar: en rollhöjning, ett platsantal och ett nytt teamfält. Omordningen var brus. Den befordringen från editor till admin är precis den sorts sak du vill fånga i en granskning, och den är lätt att missa när den är begravd under tjugo rader falska positiver.

Eliminera formateringsbrus på kommandoraden

Om dina filer redan finns på disk fungerar samma idé med "formatera och sortera" med två korta kommandon. Flaggan -S talar om för jq att sortera objektnycklar; att röra båda filerna genom det normaliserar dem så att en vanlig diff är ärlig:

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

Nu rapporterar diff bara värden som verkligen har ändrats, eftersom båda filerna har samma indragning och samma nyckelordning. Det här är terminalmotsvarigheten till att klicka på Formatera och sortera nycklar i webbläsaren.

Textdiff vs strukturell diff

Allt ovan är en textdiff: snabb, visuell och perfekt för en människa som läser en ändring. En strukturell diff går längre och beskriver ändringen som data. Standarden för det är JSON Patch, definierad i RFC 6902, som uttrycker redigeringar som operationer som replace och add vid en given sökväg. Du vill ha en strukturell diff när ett program behöver tillämpa ändringen, inte bara en person som öga för det. För daglig granskning räcker en textdiff med sorterade nycklar gott.

Vanliga fallgropar att hålla utkik efter

FallgropVarför den biterÅtgärd
NummerprecisionHeltal över 2^53 − 1 tappar precision i JavaScriptJämför stora ID:n som strängar; se MAX_SAFE_INTEGER
Unicode-escape"café" och "café" är samma sträng, olika bytesFormatera båda sidor, vilket normaliserar kodningen
Dubbletter av nycklarDe flesta parsers behåller tyst den sistaValidera JSON:en innan du litar på diff:en
Avslutande kommateckenInte giltig JSON; en fil kanske inte ens kan parsasFixa syntaxen först, validatorn flaggar det
Sträng vs nummer"5" och 5 ser lika ut men är olika typerDet här är en verklig förändring, ignorera den inte

Relaterade verktyg

JSON är sällan det enda formatet du har att göra med. Om du jämför konfiguration mellan miljöer tillämpar YAML-jämförelse samma idé på YAML. Att granska ändringar mellan två API-anrop är vad API-responsdiff-verktyget är byggt för, och beroendebumpar är enklast att läsa på package.json diff-sidan.

Vanliga frågor

Laddar jämförelse av JSON-filer online upp dem någonstans?
På comparetext.org körs diff:en i din webbläsare. De två JSON-filerna jämförs av JavaScript på din egen dator, så inget skickas till en server om du inte uttryckligen klickar på Spara eller Dela. Det gör det säkert för konfigurationsfiler, API-svar och annan data du inte skulle vilja klistra in på en slumpmässig webbplats som laddar upp vid varje knapptryckning.
Varför visar mina två JSON-filer varje rad som annorlunda?
Nästan alltid är det formatering, inte verkliga ändringar. En fil är minifierad eller indragen med tabbar, den andra med två mellanslag, eller objektnycklarna är i en annan ordning. Klicka på Formatera på båda sidor så att de använder samma indragning, sortera sedan nycklarna så att ordning slutar spela roll. Därefter krymper diff:en vanligtvis till det fåtal värden som genuint har ändrats.
Hur jämför jag JSON med ignorerad nyckelordning?
JSON-objektnycklar har ingen definierad ordning, så {"a":1,"b":2} och {"b":2,"a":1} är lika. För att få en textdiff att hålla med, sortera nycklarna på båda sidor innan jämförelse. I webbläsaren, använd alternativet kanonisera (sortera nycklar). På kommandoraden gör jq det: jq -S . file.json. När båda filerna har nycklar i samma sorterade ordning dyker bara verkliga värdeändringar upp.
Kan jag jämföra stora JSON-filer utan att sidan fryser?
Ja, upp till en punkt. En raddiff förblir snabb på filer med tusentals rader eftersom den jämför hela rader först istället för varje tecken. Mycket stora filer (flera megabyte) hanteras bättre med ett kommandoradsverktyg som jq eller git diff, som strömmar datan. För allt du bekvämt kan scrolla igenom i en webbläsare är en online-diff det snabbare alternativet.
Vad är skillnaden mellan en textdiff och en strukturell diff av JSON?
En textdiff jämför filerna rad för rad, på samma sätt som den skulle jämföra två uppsatser. En strukturell diff förstår JSON, så den vet att en omordnad nyckel inte är en förändring och att ett värde som har flyttats inuti en array är en flytt, inte en borttagning plus ett tillägg. Textdiff:ar är snabbare och tillräckligt bra för de flesta granskningar. Strukturella diff:ar (till exempel JSON Patch per RFC 6902) spelar roll när du behöver beskriva en förändring som data ett program kan tillämpa.
Hur jämför jag två API-svar?
Spara varje svar till en fil eller kopiera det från fliken nätverk i din webbläsare, klistra sedan in det gamla svaret till vänster och det nya till höger. Formatera båda så att indragning stämmer, och sortera nycklar om API:et inte returnerar dem i en stabil ordning. Verktyget api-response-diff är finjusterat för exakt detta: att hitta ett omdöpt fält, en ändrad statuskod, eller ett värde som flippade från en sträng till ett nummer mellan två anrop.

Vill du prova? Klistra in dina filer i JSON-jämförelseverktyget och se vad som har ändrats.