JSON (JavaScript Object Notation) je oblíbený textový formát určený k ukládání a výměně hierarchicky strukturovaných dat. Během několika posledních let se JSON prosadil především jako silně odlehčená náhrada XML či jako alternativa k němu. Jeho syntaxe je převzata, jak už název napovídá, z jazyka JavaScript, JSON však na JavaScriptu nijak přímo nezávisí a je velmi dobře použitelný i v jiných programovacích jazycích.
Softwarový vývojář, který od XML konvertoval k JSON, musí zajisté ocenit, jak snadno a elegantně se s tímto formátem pracuje. Žádné DOMy či jiné těžkotonážní struktury, data zapsaná v JSON se jednoduše naparsují do základních datových typů, jakým je třeba object v JavaScriptu nebo dictionary v Pythonu. Záhy ale člověk také zjistí, že vše ostatní je v podstatě na něm. Pro JSON totiž dosud nejsou k dispozici nástroje a technologie typu XPath, XSLT či XQuery, které jsou v případě XML schopny zvládnout mnoho černé práce. Aplikace využívající JSON se buď bez těchto věcí musí obejít anebo implementovat vlastní náhradu. Příkladem takové vlastní implementace je třeba dotazovací jazyk v databázi MongoDB.
Pracovní skupina pro oblast aplikací při IETF (appsawg) se proto před časem chopila standardizace dvou užitečných rozšíření pro práci s JSON daty – JSON Pointer a JSON Patch. Oba standardy vyšly těsně po Velikonocích jako dokumenty RFC, a tak si o nich něco povězme.
JSON Pointer
První z navržených standardů, RFC 6901, definuje výrazy, jimiž je možno adresovat uzly ve stromové struktuře JSON dokumentu. Jde tedy vlastně o náhradu výrazů XPath, ovšem náhradu velmi dietní. JSON Pointer neumožňuje žádné testování podmínek ani osy typu preceding-sibling::
, jak je známe z XPath.
Nejjednodušším JSON Pointerem je prázdný řetěz, jenž odpovídá celému JSON dokumentu. Jinak musí každý JSON Pointer začínat lomítkem, za nímž následuje neprázdná posloupnost identifikátorů jednotlivých uzlů oddělených lomítky. V daném cílovém dokumentu se vždy začíná od kořene (nejvyšší úrovně) a s každým identifikátorem se sestupuje o úroveň níže. Identifikátorem může být buď řetěz znaků anebo číslo, podle toho, jakého typu je aktuální hodnota. Konkrétně:
- Je-li aktuální hodnotou objekt, pak následujícím identifikátorem musí být řetěz unicodových znaků, který udává jméno některé položky v objektu (v terminologii JSON se položka nazývá member).
- Je-li aktuální hodnotou pole (array), je následujícím identifikátorem dekadické číslo udávající index prvku v poli. Indexem prvního prvku pole je nula.
Pro adresování prvků pole lze kromě čísla použít také znak „ -
” (minus), jímž se označuje imaginární prvek bezprostředně následující za posledním existujícím prvkem pole. Za okamžik si ukážeme, jak tohoto způsobu adresace využívá JSON Patch.
Aktuální hodnota, ke které dospějeme po zpracování posledního identifikátoru, je pak výsledkem celého JSON Pointeru.
Dva znaky, „ ~
” a „ /
”, mají ve výrazech JSON Pointer speciální význam. Pokud se vyskytují v identifikátoru, je nutno je zakódovat pomocí dvojic „ ~0
” (vlnovka) a „ ~1
” (lomítko). Dalšími technickými detaily se zabývat nebudeme, dají se najít přímo v citovaném RFC. Raději si ukažme pár příkladů s využitím tohoto JSON objektu:
{ "město": [ { "jméno": "Praha", "populace": 1272690 }, { "jméno": "Brno", "populace": 384277 } ] }
Tři platné JSON Pointery spolu s výslednými hodnotami jsou uvedeny v tabulce.
JSON Pointer | Výsledek |
---|---|
"" |
celý dokument |
"/město/0" |
první prvek pole "město" |
"/město/1/populace" |
384277 |
JSON Patch
RFC 6902 obsahuje specifikaci dokumentů typu JSON Patch – formálně jde o media type application/json-patch+json
. JSON Patch dokument reprezentuje sérii změn, které se mají provést s daným JSON dokumentem. Hlavní využití se předpokládá v souvislosti s nedávno zavedenou metodou HTTP PATCH, viz RFC 5789.
Obsahem dokumentu JSON Patch je pole. Každým jeho prvkem je objekt popisující jednu „záplatu” (patch). Ukažme si nejprve příklad, který je zaměřen na výše uvedený JSON dokument s Prahou a Brnem:
[ { "op": "add", "path": "/město/-", "value": { "jméno": "České Budějovice", "populace": 93883 } }, { "op": "test", "path": "/město/0/jméno", "value": "Praha" }, { "op": "add", "path": "/město/0/poznámka", "value": "hlavní město" } ]
Vyhodnocení tohoto JSON Patch dokumentu vede postupně k následujícím akcím a změnám cílového dokumentu:
- Na konec pole
město
se připojí nový prvek obsahující data pro České Budějovice. - Testuje se, zda je hodnota položky
"jméno"
v prvním prvku pole"město"
rovna řetězu"Praha"
. Protože tomu tak je, pokračuje se další záplatou. - Do prvního pole
mesto
(pro Prahu) se přidá položka se jménem"poznámka"
a hodnotou"hlavní město"
.
Jednotlivé záplaty se vyhodnocují a aplikují v tom pořadí, jak jdou v poli za sebou, a to až do konce anebo do první chyby.
Každá záplata má dvě povinné položky: "op"
a "path"
. První z nich specifikuje operaci a druhá pak obsahuje JSON Pointer, který ukazuje na hodnotu, s níž se má operace provést. Každá z operací pak má obvykle ještě jednu povinnou položku s dalším parametrem.
JSON Patch dává na výběr následujících šest operací:
"add"
- Záplata s touto operací musí obsahovat také položku
"value"
. Pokud je JSON Pointer uvedený v"path"
indexem pole, vloží se na příslušnou pozici pole hodnota položky"value"
a všechny následující prvky pole se posunou o jedno místo dozadu. Je-li místo číselného indexu uvedena pomlčka, připojí se nový prvek na konec pole. Když hodnota"path"
ukazuje na položku objektu, záleží na tom, jestli tato položka již existuje. Pokud ano, její hodnota se přepíše obsahem"value"
. A když neexistuje, vytvoří se nová položka s touto hodnotou. "remove"
- Touto operací se odstraní položka objektu nebo prvek pole, na nějž ukazuje JSON Pointer
"path"
. V případě pole se všechny následující prvky posunou o jednu pozici vpřed. "replace"
- Tato operace nahrazuje existující hodnotu novou. Funguje úplně stejně jako
"remove"
a za ní bezprostředně následující"add"
se stejnou hodnotou"path"
. U operace"replace"
musí být uvedena položka"value"
, v níž je obsažena nová hodnota. "move"
- Pomocí této operace je možné přesunout zadanou hodnotu z jejího původního místa na jiné. Další povinnou položkou je zde
"from"
, což je JSON Pointer určující původní umístění, to nové je pak obsaženo v"path"
. "copy"
- Touto operací lze zadanou hodnotu kopírovat. Podobně jako u
"move"
udává položka"from"
původní umístění. Hodnota na tomto místě zůstane, ale navíc se zkopíruje do nového umístění zadaného v"path"
. "test"
- Smyslem poslední operace je umožnit podmíněné přerušení uprostřed série záplat. Jedinou podmínkou, kterou lze testovat, je rovnost – hodnota uvedená v povinné položce
"value"
se musí shodovat s hodnotou v cílovém dokumentu, na niž ukazuje"path"
. Pokud nejsou stejné, nastává chyba.
Aby byla specifikace kompletní, je třeba ještě ošetřit různé chybové situace, a také stanovit, co u operace "test"
přesně znamená rovnost. V těchto technikáliích ale nenajdeme nic překvapivého. Například rovnost dvou objektů se definuje podle očekávání rekurzivně: oba objekty musí obsahovat stejné položky a u každé dvojice odpovídajících položek musí nastat rovnost.
Co čeká JSON dále?
V IETF se připravuje ustavení nové pracovní skupiny s názvem JSON. Pohled do předběžného návrhu její charty nás ale přesvědčí, že se žádné převratné změny ani rozšíření nechystají. V plánu jsou totiž pouze následující, v podstatě administrativní, úkony:
- Původní specifikace JSON (RFC 4627) byla vydána jen jako informativní dokument. Takový statut podle procesních pravidel IETF neumožňuje toto RFC citovat jako tzv. normativní referenci. Nové vydání specifikace proto bude mít statut proposed standard a opraví také všechny chyby, které byly v RFC 4627 nalezeny.
- Standardizace formátu JSON běží aktuálně po dvou kolejích – kromě IETF se jí zabývá i nezisková mezinárodní organizaceEcma International, jež vydává standardy jazyka JavaScript, známé pod jménem ECMAScript. Cílem nové revize RFC 4627 proto také je zdokumentovat a pokud možno odstranit rozdíly mezi oběma specifikacemi, zejména pokud jde o pravidla parsování JSON textu.
Lze předpokládat, že oba plánované body zvládne pracovní skupina JSON celkem rychle. Otevřenou otázkou je, jestli poté připraví novou chartu, která by mohla zahrnout i některé nové a zajímavé náměty, objevující se v živé diskusi nad stávající chartou. Jedním z kandidátů je třeba JSON Schema, tedy analogie schémových jazyků, jaké známe z XML – W3C XML Schema, RELAX NG či Schematron. Proti tomuto návrhu ale vystupuje poměrně početná skupina, pro niž je absence schémového jazyka pro JSON naopak významnou předností. Takže uvidíme.