Vai al contenuto
jsonbeautifiers
Italiano

Parser JSON

Analizza un payload e vedine tipi, profondità, numero di chiavi e tutti i percorsi.

Input

Nulla di ciò che incolli lascia il tuo browser. L’allowlist connect-src ne fa una garanzia del browser anziché una promessa. Verificalo tu stesso

Analizzare trasforma il testo in struttura. Questa pagina ti mostra che cosa ne è uscito: i tipi, la profondità di annidamento, quante chiavi e quanti array ci sono, quali numeri non sopravvivranno a un parser JavaScript e dove sono le chiavi duplicate.

È la pagina da aprire quando ti hanno passato un payload e la prima domanda è che cosa ci sia davvero dentro.

Che cosa dicono le statistiche

Ognuna risponde a una domanda che si pone quando stai per scrivere codice su un documento.

Profondità massima
Fin dove arriva l’annidamento. Sopra qualche centinaio di livelli, controlla che cosa fanno i tuoi consumatori. Misurato qui: V8 analizza un milione di livelli ma si rifiuta di serializzare oltre circa 4.800, e lo scanner in C di CPython arriva intorno a 17.000 nonostante un limite di ricorsione Python di 1.000.
Numero di chiavi e di oggetti
Una misura grossolana del lavoro che farà un mapper o un ORM, e di quanto occuperà l’albero in memoria.
Numeri non sicuri
Quanti interi superano 2^53-1. Se non è zero, qualsiasi consumatore JavaScript sta già leggendo valori diversi da quelli presenti nel file.
Chiavi duplicate
Quante chiavi di oggetto sono state definite due volte, con la posizione di ciascuna.

Analizzare non è validare una forma

Un documento può analizzarsi alla perfezione ed esserti comunque inutile: un campo rinominato, un numero inviato come stringa, un array dove ti aspettavi un oggetto. L’analisi controlla la grammatica, non il contratto.

Per il contratto, genera un JSON Schema da un payload di cui ti fidi e valida i payload successivi contro quello.

In che cosa questo parser differisce da JSON.parse

È iterativo anziché ricorsivo, quindi la profondità è limitata solo dalla memoria. Registra il testo sorgente esatto di ogni numero, quindi nulla viene arrotondato in silenzio. Tiene traccia della posizione di ogni token, quindi gli errori hanno riga e colonna. E dopo un errore si riprende invece di fermarsi, quindi un documento rotto segnala tutti i problemi in una passata.

Il costo di tutto questo è la velocità: qui circa 12-16 MB al secondo contro i 60-70 di un JSON.parse nativo. È il prezzo dell’informazione, ed è il motivo per cui il lavoro gira in un worker in background.

How to do this in code

Analizzare nel codice, comprese le opzioni che di solito si scoprono troppo tardi.

js JavaScript

Il reviver non può recuperare le cifre originali: quando viene eseguito, il numero è già stato convertito in un float.

const value = JSON.parse(text);

// The reviver runs on every key and value, which is how you
// intercept large integers before precision is lost.
const value2 = JSON.parse(text, function (key, val) {
  if (typeof val === 'number' && !Number.isSafeInteger(val)) {
    // this[key] is the raw value; the original TEXT is not
    // available here, which is the limitation.
    console.warn('unsafe integer at', key);
  }
  return val;
});
py Python

object_pairs_hook è l’unico modo portabile di rilevare chiavi duplicate in Python.

import json
from decimal import Decimal

# parse_float and parse_int receive the raw TEXT of the number,
# so unlike JavaScript you can keep full precision.
data = json.loads(text, parse_float=Decimal, parse_int=int)

# Detect duplicate keys instead of silently keeping the last
def no_dupes(pairs):
    seen = {}
    for k, v in pairs:
        if k in seen:
            raise ValueError(f'duplicate key: {k}')
        seen[k] = v
    return seen

data = json.loads(text, object_pairs_hook=no_dupes)
go Go
// UseNumber keeps the original text instead of converting
// to float64, so large integers survive.
dec := json.NewDecoder(bytes.NewReader(data))
dec.UseNumber()

var v any
if err := dec.Decode(&v); err != nil {
    return err
}
java Java
ObjectMapper mapper = new ObjectMapper();

// Fail loudly on duplicates rather than keeping the last one
mapper.enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY);

// Keep big integers exact
mapper.enable(DeserializationFeature.USE_BIG_INTEGER_FOR_INTS);

Domande frequenti

Perché il mio numero è diverso dopo l’analisi?
Perché i numeri JSON non hanno limiti di dimensione e i double IEEE 754 sì. Qualsiasi intero sopra 2^53-1 e molti decimali non possono essere rappresentati esattamente. Python, Go e Java offrono tutti un modo per conservare il testo originale; JavaScript no, ed è per questo che gli ID grandi andrebbero inviati come stringhe.
Che fine fanno le chiavi duplicate?
La RFC 8259 lo lascia indefinito. JavaScript e Python tengono l’ultima occorrenza, alcune configurazioni Go e Java rifiutano il documento, qualche parser tiene la prima. Non farci mai affidamento. Questa pagina segnala ogni duplicato con entrambe le posizioni.