Confronto JSON
Confronta due oggetti JSON e visualizza le differenze evidenziate.
Informazioni sul confronto JSON
Il confronto JSON (chiamato anche diff JSON) identifica le differenze tra due strutture JSON. A differenza di un diff di testo semplice, un confronto che comprende il JSON conosce le chiavi e i valori, e può quindi indicarti esattamente quali proprietà sono state aggiunte, rimosse o modificate · indipendentemente dall'ordine delle chiavi.
Questo strumento esegue un confronto profondo e ricorsivo di due oggetti JSON. Gestisce oggetti annidati, array, stringhe, numeri, booleani e valori null. Tutta l'elaborazione avviene localmente nel tuo browser.
Una breve storia di JSON
La biografia di JSON è più breve del linguaggio di programmazione medio e molto meno drammatica. L'acronimo è nato a State Software, Inc., una piccola azienda che Douglas Crockford e Chip Morningstar hanno fondato nel marzo 2001 per costruire quelle che sarebbero state chiamate applicazioni web Ajax. Il primo messaggio JSON è stato inviato nell'aprile 2001, da un computer nel garage di Morningstar nella Bay Area. Crockford non rivendica di aver inventato JSON, l'ha staccato dalla sintassi del literal di oggetto JavaScript, gli ha dato un nome, e ha messo su un sito web. Ha acquisito json.org nel 2002 e vi ha pubblicato una grammatica con diagrammi ferroviari. Per quattro anni JSON si è propagato per passaparola e un lento gocciolio di implementazioni di librerie. Nel dicembre 2005, Yahoo! ha iniziato a offrire alcuni dei suoi servizi web in JSON, il momento che la maggior parte degli storici indica come l'attraversamento di JSON nel mainstream. La standardizzazione è arrivata a ondate: RFC 4627 (luglio 2006), redatto dallo stesso Crockford, con status informativo piuttosto che standards-track; ECMA-404 prima edizione (ottobre 2013); RFC 7159 (marzo 2014), che ha messo JSON sull'IETF Standards Track e ha allentato il requisito che il valore di top-level fosse un oggetto o array. Le versioni attuali sono RFC 8259 (dicembre 2017), ora Internet Standard STD 90, e ECMA-404 seconda edizione (dicembre 2017). I due sono intenzionalmente identici nella grammatica; il testo IETF aggiunge linee guida di sicurezza e interoperabilità che il testo Ecma omette deliberatamente.
Due famiglie algoritmiche: line diff e structural diff
L'informatica pensa al diffing dagli anni 1970. Douglas McIlroy (lo stesso McIlroy che ha inventato le pipe di Unix) e James W. Hunt hanno scritto il diff Unix originale all'inizio degli anni 1970; è stato distribuito come parte della 5a edizione di Unix nel 1974, con l'algoritmo sottostante documentato nel Bell Labs Computing Science Technical Report #41 nel giugno 1976. Hunt-McIlroy è costruito sul problema della sottosequenza comune più lunga, trovare la sequenza più lunga di righe che appare in ordine in entrambi gli input, e tutto ciò che non è in quella sequenza è o una cancellazione o un inserimento. Un decennio dopo, Eugene W. Myers ha pubblicato "An O(ND) Difference Algorithm and Its Variations" in Algorithmica Vol 1, Issue 2 (1986), riformulando il problema come ricerca del percorso più breve su un "edit graph", la base per un'implementazione più veloce del diff Unix che girava da due a quattro volte più velocemente del suo predecessore. Oggi, git diff usa di default un algoritmo histogram in LibXDiff, generalmente più veloce del Myers vaniglia e producendo output più leggibile, specialmente intorno ai blocchi spostati. Patience diff (Bram Cohen, 2008) è un altro raffinamento LCS che dà priorità a righe di ancoraggio uniche. Tutte variazioni su un tema: LCS riga-per-riga, trattando l'input come una sequenza piatta di token opachi. Nessuno di loro sa cosa sia JSON.
La famiglia structural diff adotta un approccio diverso: cammina entrambi gli input in parallelo, confrontando le primitive con uguaglianza stretta, calcolando l'unione delle chiavi di oggetto (presente-solo-a-sinistra è "rimosso", presente-solo-a-destra è "aggiunto", presente-in-entrambi significa ricorsione), e camminando gli array per indice. Per ogni posizione, ricorri. Se un array è più lungo, gli elementi extra sono aggiunti o rimossi. I cambi di tipo (numero vs stringa, oggetto vs array) diventano voci "type changed". Questo è l'algoritmo che jsondiffpatch implementa come caso base, ed è l'algoritmo che questo strumento implementa. La sua forza è che l'output è significativo: ogni cambio segnalato ha un percorso all'interno del documento (user.address.city, items[3].price) e una semantica chiara. La sua debolezza è il terzo passo, il confronto di array per indice, che produce sciocchezze ogni volta che un elemento viene inserito vicino alla parte anteriore di un array lungo.
Il problema più difficile nel diffing JSON: gli array
Supponi che il tuo JSON "before" contenga l'array ["alpha", "beta", "gamma", "delta"] e il tuo JSON "after" contenga ["alpha", "new", "beta", "gamma", "delta"]. Un diff basato sull'indice ingenuo riporta quattro cambiamenti: l'indice 1 è cambiato da "beta" a "new"; l'indice 2 è cambiato da "gamma" a "beta"; l'indice 3 è cambiato da "delta" a "gamma"; l'indice 4 ha aggiunto "delta". Un umano che guarda questo direbbe che c'è un cambiamento: un singolo inserimento all'indice 1. Questo è lo stesso problema LCS che la famiglia line-diff ha risolto negli anni 1970, applicato ad array di valori JSON piuttosto che ad array di righe di testo. jsondiffpatch fa esattamente questo, calcola l'LCS dei due array ed emette inserimenti e cancellazioni relative ad esso. Per array di primitive questo funziona bene. Per array di oggetti no: [{id: 1, name: "Alice"}] contro [{id: 1, name: "Alicia"}] non hanno sottosequenza comune per uguaglianza di riferimento, quindi LCS ingenuo riporta "cancella l'intero elemento sinistro, aggiungi l'intero elemento destro" quando la verità è che un campo di un elemento è cambiato. La soluzione di jsondiffpatch è il callback objectHash: il chiamante fornisce una funzione che mappa ogni oggetto a una chiave di identità (tipicamente obj => obj.id), e il diff abbina gli elementi dell'array per identità piuttosto che per riferimento. Questo è un problema generale difficile che nessuno ha risolto completamente. Lo strumento Absolutool, per la sua stessa FAQ, confronta gli array per indice, non implementa LCS o objectHash. Questa è una scelta di scope deliberata per un piccolo strumento gratuito: è eccellente sui diff di oggetti e più debole su array dove gli elementi sono stati inseriti o riordinati.
JSON Patch (RFC 6902): diff come formato di trasporto
RFC 6902, "JavaScript Object Notation (JSON) Patch," è stato pubblicato nell'aprile 2013. Definisce il media type application/json-patch+json e un linguaggio di patch a sei operazioni: add, remove, replace, move, copy, test. Un patch è esso stesso un documento JSON, un array di oggetti operazione, ognuno con una chiave op, una chiave path (un JSON Pointer alla posizione target), e un campo value o from come appropriato. Le operazioni sono applicate in ordine, atomicamente: se una qualsiasi fallisce, l'intero patch viene rifiutato. La sintassi del path viene da RFC 6901, "JSON Pointer," un documento compagno pubblicato lo stesso mese, una piccola sintassi di stringa di token di riferimento separati da slash (/user/address/city significa "il valore alla chiave city all'interno di address all'interno di user"; /items/3 significa "il quarto elemento di items", zero-indicizzato). Poiché / e ~ sono speciali, vengono escapati a ~1 e ~0 rispettivamente (in quell'ordine, decodificare ~1 prima per evitare bug di doppia decodifica). JSON Patch è il formato di output giusto per uno strumento di diff JSON che vuole alimentare il risultato a un'altra macchina. Il metodo HTTP PATCH (RFC 5789) è stato progettato esattamente per questo tipo di payload di aggiornamento parziale. Kubernetes supporta RFC 6902 insieme al proprio formato strategic-merge-patch. Questo strumento attualmente non emette JSON Patch, è una direzione di feature futura, non attuale.
JSON Merge Patch (RFC 7396): l'alternativa più semplice e lossy
RFC 7396, "JSON Merge Patch," è stato pubblicato nell'ottobre 2014 da Paul Hoffman e James Snell. Non usa alcuna operazione, il documento patch è semplicemente un oggetto JSON parziale che si sovrappone sull'originale. Qualsiasi campo presente nel patch sovrascrive il campo corrispondente nell'originale; qualsiasi campo impostato a null nel patch rimuove quel campo; qualsiasi campo assente dal patch rimane invariato; gli array vengono sostituiti interamente, mai uniti. Merge Patch è conciso e facile da scrivere a mano. Il compromesso è la perdita di espressività: non c'è modo di impostare il valore di un campo a null letterale (perché null significa "cancella"); nessun modo di modificare un singolo elemento di un array (l'intero array viene sostituito); nessun modo di esprimere uno spostamento o una copia; nessun modo di distinguere "non ho toccato questo campo" da "voglio impostarlo al suo valore attuale". Per la maggior parte degli aggiornamenti API quotidiani queste limitazioni sono accettabili, motivo per cui Merge Patch è il più popolare dei due formati. RFC 6902 vince negli scenari dove una qualsiasi delle limitazioni morde. Kubernetes usa entrambi i formati deliberatamente, scegliendo quello giusto per ogni contesto.
Come renderizza il diff visivo
Ci sono tre convenzioni visive comuni per visualizzare un diff strutturale. Side-by-side, due colonne, originale a sinistra, modificato a destra, con righe corrispondenti allineate (il layout che questo strumento usa per i suoi input). Diff unificato inline, una singola colonna che mostra righe rimosse (tipicamente prefissate con - e colorate di rosso), righe aggiunte (+, verde), e righe di contesto invariate (nessun prefisso, testo semplice), il layout che git diff usa di default. Vista ad albero, renderizza il JSON come un albero pieghevole, con i nodi cambiati evidenziati e i nodi invariati ripiegati. Le convenzioni di colore sono notevolmente coerenti in tutto l'ecosistema: verde per aggiunte, rosso per rimozioni, giallo o ambra per valori cambiati, grigio neutro per invariato. Questo strumento segue la convenzione esattamente: verde chiaro per aggiunte, rosso chiaro per rimozioni, giallo chiaro per cambiamenti. La maggior parte degli utenti riconoscerà i colori da GitHub, GitLab, BitBucket, ogni vista diff IDE e dozzine di strumenti online.
Usi comuni
- Confrontare le risposte API prima e dopo una modifica del codice
- Trovare le differenze tra file di configurazione
- Revisione di lockfile generati.
package-lock.json,yarn.lock,poetry.lock,Cargo.locketerraform.tfstatesono tutti file JSON o adiacenti a JSON generati dalla macchina che cambiano in modi rumorosi durante lo sviluppo normale. Un diff JSON-aware è molto più utile di un diff di testo per capire cosa si è effettivamente mosso. - Verifica di round-trip di serializzazione. Serializza una riga di database in JSON, passala attraverso una rete, deserializzala, ri-serializzala. È cambiato qualcosa? Un diff cattura bug silenziosi nei serializzatori personalizzati, specialmente intorno alle date, alla precisione numerica e alla gestione di null.
- Test di regressione di output JSON. Cattura uno snapshot di un output JSON noto come buono; fai il diff di ogni esecuzione successiva contro lo snapshot e fa fallire il test se qualcosa è cambiato.
- Confronto di bozze di schema. I documenti JSON Schema e OpenAPI sono essi stessi JSON. Fare il diff di due versioni di uno schema rivela esattamente quali campi sono diventati required, optional o hanno avuto i loro tipi ristretti.
- Verificare l'esattezza di una migrazione di dati
Casi limite che vale la pena conoscere
Precisione numerica. RFC 8259 dice che i numeri JSON sono arbitrary-precision e non pone alcun limite superiore su quante cifre può avere un numero. JavaScript, tuttavia, parsa ogni numero come un double IEEE 754 a 64 bit. Sopra Number.MAX_SAFE_INTEGER (253 − 1 = 9.007.199.254.740.991), gli interi possono perdere silenziosamente precisione quando vengono fatti round-trip attraverso un diff basato su JavaScript. Lo stesso problema affligge il floating-point, 0.1 + 0.2 non è famosamente esattamente 0.3 in IEEE 754. JSON stretto inoltre non permette virgole finali e commenti; entrambi sono errori di sintassi per RFC 8259. JSON5 (json5.org) è un superset formale che permette commenti, virgole finali, virgolette singole, chiavi senza virgolette, numeri hex, punti decimali iniziali/finali, e Infinity/NaN. JSONC è la modalità "JSON with Comments" di Microsoft usata nei file di impostazioni di VS Code. Questo strumento usa JSON.parse() e quindi rifiuterà entrambi, rimuovi commenti e virgole finali prima di incollare.
Stringhe di data. JSON non ha un tipo data nativo. Le date sono tipicamente codificate come stringhe, con lo standard de facto che è ISO 8601 (e specificamente il profilo RFC 3339 che la maggior parte delle API internet usa): YYYY-MM-DDTHH:MM:SS[.fff]Z. Un diff che confronta le date come stringhe riporterà 2024-01-01T00:00:00Z e 2024-01-01T00:00:00.000Z come diverse, anche se rappresentano lo stesso istante, perché le stringhe differiscono. Chiavi duplicate. RFC 8259 §4 afferma "i nomi all'interno di un oggetto DOVREBBERO essere unici", lo SHOULD è normativamente più debole di MUST. JSON.parse() di JavaScript accetta chiavi duplicate e silenziosamente mantiene l'ultima; altri parser possono mantenere la prima o sollevare un errore. null vs mancante. {"a": null} e {} sono valori JSON diversi. Questo strumento riporta il primo come "la chiave a ha valore null" e il secondo come "nessuna chiave a", sono correttamente distinti. Il trattamento di null di JSON Merge Patch come segnale di cancellazione è un'ammissione a livello di formato che la distinzione è reale e complicata.
L'ecosistema nel 2026
Il diff JSON open-source è dominato da una manciata di librerie. jsondiffpatch di Benjamin Eidelman, pubblicato per la prima volta nel 2012, è la libreria JavaScript de facto: ~5k stelle GitHub, supporta objectHash, array LCS, patch inversi e un formattatore HTML visivo. json-diff di Andrey Tarantsov è lo strumento Node CLI canonico, con lo stesso nome condiviso da implementazioni parallele in Python, Go e Rust. DeepDiff di Sep Dehpour è la libreria Python dominante, diff ricorsivo con opzioni per ignorare l'ordine, ignorare i cambi di tipo numerico, e una serie di controlli a grana fine. Il diffing di JsonNode della Linux Foundation in Jackson (Java) è la scelta JVM standard. jq non ha un comando diff nativo ma la sua famiglia di operatori = e // può esprimere semplici confronti strutturali. Il diff integrato di VS Code gestisce JSON tramite modalità testo; l'estensione JSON Tools aggiunge il confronto JSON-aware. Strumenti online come Diffchecker offrono modalità JSON che sono essenzialmente lo stesso walk ricorsivo che questo strumento implementa, spesso stratificato sopra le stesse librerie.
Perché il solo-browser conta qui
Fare il diff di due payload JSON su un server richiede di caricare entrambi. Per esempi ordinari di dati pubblici questo è innocuo. Per risposte API che contengono token di autenticazione, PII cliente, record interni di dipendenti, segreti di configurazione o dati di prodotti non rilasciati, non lo è. Anche dopo che il diff finisce, quei payload rimangono nei log del server, possibilmente in una cache CDN, possibilmente in una pipeline di analisi, possibilmente in un backup. Un diff solo-browser non trasmette mai, il JSON viene parsato e camminato interamente nel tuo tab. Puoi verificare aprendo il tab Network di DevTools mentre clicchi Confronta; non ci sono richieste in uscita. Per confrontare risposte API contro una baseline, debuggare il drift di configurazione tra ambienti, o auditare cambiamenti in un lockfile che contiene URL di pacchetti interni, "il JSON non lascia mai il mio dispositivo" è l'architettura che rende lo strumento sicuro da usare su dati di produzione reali.
Domande frequenti
L'ordine delle chiavi influisce sul confronto?
No. Gli oggetti JSON non sono ordinati secondo la specifica, quindi {"a":1, "b":2} e {"b":2, "a":1} sono trattati come identici. Solo le differenze reali di valori vengono segnalate.
Come vengono confrontati gli array?
Gli array sono confrontati per indice. Se l'array all'indice 2 differisce tra i due input, questo indice specifico viene segnalato. Anche gli elementi aggiunti o rimossi alla fine dell'array vengono rilevati.
Cosa succede con oggetti profondamente annidati?
Il confronto è completamente ricorsivo. Gli oggetti e gli array annidati a qualsiasi profondità sono confrontati proprietà per proprietà. L'output mostra il percorso completo di ogni differenza (per es. «user.address.city»).
Perché il mio confronto di interi grandi sembra sbagliato?
JavaScript parsa ogni numero JSON come un double IEEE 754 a 64 bit. Sopra Number.MAX_SAFE_INTEGER (253 − 1 = 9.007.199.254.740.991), gli interi possono perdere precisione silenziosamente. Quindi un file JSON contenente 9007199254740993 può confrontarsi come identico a un file contenente 9007199254740992. Questa è una limitazione della rappresentazione numerica sottostante, non dello strumento di diff. Se stai facendo il diff di dati che contengono ID a 64 bit (ID snowflake di Twitter, ID Discord, chiavi di database grandi), fai in modo che il tuo serializzatore li emetta come stringhe invece di numeri. Il confronto in floating-point ha lo stesso caveat: 0.1 + 0.2 non è famosamente esattamente 0.3 in IEEE 754.
Posso confrontare JSON5 o JSONC (JSON con commenti)?
Non direttamente. Questo strumento usa il JSON.parse() integrato del browser, che segue rigorosamente RFC 8259, commenti, virgole finali, stringhe a virgolette singole e chiavi senza virgolette sono errori di sintassi. Se il tuo input è JSON5 (json5.org) o JSONC in stile VS Code, rimuovi prima i commenti e le virgole finali, o eseguilo attraverso uno strumento come jsonc-parser per convertire in JSON stretto prima di incollare.
Il mio JSON viene inviato a un server?
No. Il confronto gira interamente nel tuo browser tramite JavaScript. Il JSON incollato non attraversa mai la rete, verifica nel tab Network di DevTools mentre clicchi Confronta, o porta la pagina offline dopo che si carica e conferma che il diff funziona ancora. Sicuro per confrontare risposte API con token di autenticazione, file di configurazione con segreti, o export di database che contengono PII cliente.