JSON-Parser
Ein Payload parsen und Typen, Tiefe, Schlüsselanzahl und alle Pfade sehen.
Nichts, was Sie einfügen, verlässt Ihren Browser. Die connect-src Erlaubnisliste macht daraus eine Garantie des Browsers statt eines Versprechens. Selbst überprüfen
Parsen verwandelt Text in Struktur. Diese Seite zeigt Ihnen, was dabei herauskam: die Typen, die Verschachtelungstiefe, wie viele Schlüssel und Arrays es gibt, welche Zahlen einen JavaScript-Parser nicht überleben und wo doppelte Schlüssel liegen.
Es ist die Seite, die man öffnet, wenn man ein Payload in die Hand gedrückt bekommen hat und die erste Frage lautet: Was steht da eigentlich drin?
Was die Kennzahlen aussagen
Jede beantwortet eine Frage, die sich stellt, kurz bevor man Code gegen ein Dokument schreibt.
- Maximale Tiefe
- Wie weit die Verschachtelung geht. Oberhalb einiger hundert Ebenen sollten Sie prüfen, was Ihre Konsumenten tun. Hier gemessen: V8 parst eine Million Ebenen, weigert sich aber, jenseits von etwa 4.800 zu serialisieren, und der C-Scanner von CPython schafft rund 17.000 trotz eines Python-Rekursionslimits von 1.000.
- Anzahl Schlüssel und Objekte
- Ein grobes Maß dafür, wie viel Arbeit ein Mapper oder ein ORM haben wird, und wie groß der Baum im Speicher wird.
- Unsichere Zahlen
- Wie viele Ganzzahlen 2^53-1 überschreiten. Steht hier nicht null, liest jeder JavaScript-Konsument bereits andere Werte, als in der Datei stehen.
- Doppelte Schlüssel
- Wie viele Objektschlüssel zweimal definiert wurden, mit der Position von jedem.
Parsen ist nicht dasselbe wie eine Gestalt prüfen
Ein Dokument kann sich einwandfrei parsen lassen und Ihnen trotzdem nichts nützen: ein umbenanntes Feld, eine als Zeichenkette gesendete Zahl, ein Array, wo ein Objekt erwartet wurde. Parsen prüft die Grammatik, nicht den Vertrag.
Für den Vertrag erzeugen Sie aus einem Payload, dem Sie trauen, ein JSON Schema und validieren künftige Payloads dagegen.
Wie sich dieser Parser von JSON.parse unterscheidet
Er arbeitet iterativ statt rekursiv, die Verschachtelungstiefe ist also nur durch den Speicher begrenzt. Er hält den exakten Quelltext jeder Zahl fest, es wird also nichts stillschweigend gerundet. Er verfolgt die Position jedes Tokens, Fehler haben also Zeile und Spalte. Und er erholt sich nach einem Fehler, statt anzuhalten, ein kaputtes Dokument meldet also alle Probleme in einem Durchgang.
Der Preis dafür ist Geschwindigkeit: hier etwa 12 bis 16 MB pro Sekunde gegenüber 60 bis 70 bei einem nativen JSON.parse. Das ist der Preis der Information, und deshalb läuft die Arbeit in einem Hintergrund-Worker.
How to do this in code
Parsen im Code, samt der Optionen, die man meistens zu spät entdeckt.
js JavaScript
Der Reviver kann die ursprünglichen Ziffern nicht zurückholen: Wenn er läuft, wurde die Zahl längst in einen Float umgewandelt.
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 ist der einzige portable Weg, doppelte Schlüssel in Python zu erkennen.
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); Häufige Fragen
- Warum ist meine Zahl nach dem Parsen anders?
- Weil JSON-Zahlen keine Größenbeschränkung haben und IEEE-754-Doubles schon. Jede Ganzzahl über 2^53-1 und viele Dezimalzahlen lassen sich nicht exakt darstellen. Python, Go und Java bieten jeweils einen Weg, den ursprünglichen Text zu behalten; JavaScript nicht - deshalb sollten große IDs als Zeichenketten gesendet werden.
- Was passiert mit doppelten Schlüsseln?
- RFC 8259 lässt das offen. JavaScript und Python behalten das letzte Vorkommen, manche Go- und Java-Konfigurationen lehnen das Dokument ab, einige Parser behalten das erste. Verlassen Sie sich nie darauf. Diese Seite meldet jedes Duplikat mit beiden Positionen.