Znění hlášky v jednotlivých prostředích
„Projde bez chyby“ u NaN neznamená správný výsledek: JSON.stringify zapíše
null a Python zapíše NaN, které jiné parsery odmítnou. Typ, který
Python nezná, hlásí vždy stejně, jen se mění jeho název (Decimal,
set, bytes). PHP json_encode výjimku nevyhodí, vrátí
false; když výsledek nekontroluješ, odešleš prázdnou odpověď. Použij
JSON_THROW_ON_ERROR.
Objekt odkazuje sám na sebe
JSON je strom a odkazy nezná. Autor s polem knih, kde každá kniha odkazuje zpět na autora, se zapsat nedá: převod by nikdy neskončil. Typicky jde o vazby rodič–potomek, entity z ORM s oboustrannými vazbami nebo uzly DOM. Rozhodni, kterou stranu vazby do JSON zapsat.
const autor = { jmeno: 'Božena Němcová', knihy: [] };
const kniha = { nazev: 'Babička', autor };
autor.knihy.push(kniha);
JSON.stringify(autor);
// TypeError: Converting circular structure to JSON
// Zpětný odkaz při převodu vynech
JSON.stringify(autor, (key, value) => (key === 'autor' ? undefined : value));
// {"jmeno":"Božena Němcová","knihy":[{"nazev":"Babička"}]} class Kniha {
constructor(nazev, autor) {
this.nazev = nazev;
this.autor = autor;
}
toJSON() {
return { nazev: this.nazev, autor: this.autor.jmeno };
}
}
// {"jmeno":"Božena Němcová","knihy":[{"nazev":"Babička","autor":"Božena Němcová"}]}
.NET umí cyklus přerušit volbou ReferenceHandler.IgnoreCycles (zpětný odkaz
zapíše jako null) nebo zapsat odkazy přes $id a $ref
volbou ReferenceHandler.Preserve. Druhá možnost ale vyžaduje, aby ji znal i příjemce.
var options = new JsonSerializerOptions { ReferenceHandler = ReferenceHandler.IgnoreCycles };
JsonSerializer.Serialize(kniha, options);
// {"Nazev":"Babi\u010Dka","Self":null} Typ, který JSON nezná
JSON má jen řetězce, čísla, logické hodnoty, null, objekty a pole. Datum,
desetinné číslo s pevnou přesností nebo velké celé číslo se musí převést na jeden z nich
a příjemce se musí dozvědět jak, obvykle ze schématu nebo dokumentace API. Datum se nejčastěji
zapisuje jako řetězec ISO 8601, velká čísla a částky jako řetězec, aby se nezaokrouhlila.
JSON.stringify({ id: 9007199254740993n },
(key, value) => (typeof value === 'bigint' ? value.toString() : value));
// {"id":"9007199254740993"} import json, datetime, decimal
def prevod(o):
if isinstance(o, (datetime.date, datetime.datetime)):
return o.isoformat()
if isinstance(o, decimal.Decimal):
return str(o)
if isinstance(o, set):
return sorted(o)
raise TypeError(f'Object of type {type(o).__name__} is not JSON serializable')
data = {'vydano': datetime.date(1855, 1, 1), 'cena': decimal.Decimal('249.90'), 'stitky': {'klasika'}}
json.dumps(data, default=prevod, ensure_ascii=False)
# {"vydano": "1855-01-01", "cena": "249.90", "stitky": ["klasika"]} JSON.stringify převede Date sám (na řetězec ISO 8601 v UTC), ale
Map a Set zapíše jako prázdný objekt {}
a undefined nebo funkce vynechá, a to bez chyby. Proč na přesnosti velkých čísel
záleží, popisuje kapitola Čísla v JSON.
NaN a Infinity
JSON.stringify({ a: NaN, b: Infinity });
// {"a":null,"b":null} žádná chyba, hodnota se ztratí
json.dumps({'a': float('nan')})
# {"a": NaN} to už není JSON, jiné parsery ho odmítnou
json.dumps({'a': float('nan')}, allow_nan=False)
# ValueError: Out of range float values are not JSON compliant: nan
Výsledek výpočtu, který skončil dělením nulou, je potřeba ošetřit před převodem: nahradit
null s jasným významem, nebo převod odmítnout. V Pythonu zapni
allow_nan=False, ať se neplatný JSON nedostane ven. Co s takovým souborem udělají
parsery, ukazuje stránka Neplatné číslo v JSON.
PHP: Malformed UTF-8 characters
json_encode pracuje jen s UTF-8. Text ve Windows-1250 nebo ISO-8859-2 (starší
databáze, CSV z Excelu, exporty účetních programů) skončí chybou
JSON_ERROR_UTF8. Převeď ho do UTF-8 u zdroje, nebo před převodem na JSON.
$nazev = "Babi\xe8ka"; // "Babička" ve Windows-1250, třeba z databáze nebo CSV
json_encode(['nazev' => $nazev]);
// false, json_last_error_msg(): Malformed UTF-8 characters, possibly incorrectly encoded
$json = json_encode(
['nazev' => iconv('Windows-1250', 'UTF-8', $nazev)],
JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE,
);
// {"nazev":"Babička"}
Pozor: mb_convert_encoding v PHP 8.4 kódování Windows-1250 nezná (zná ISO-8859-2)
a vyhodí ValueError; pro Windows-1250 použij iconv. Příznak
JSON_INVALID_UTF8_SUBSTITUTE chybu potlačí, ale písmena nahradí znakem U+FFFD
a data se ztratí. Česká kódování a jejich rozpoznání popisuje kapitola
Čeština a kódování v XML; pro JSON platí totéž.