JSON Toolkit

Hranice převodu JSON ↔ YAML a XML

Shrnutí: Tvzení, že JSON je podmnožinou YAML, zaručuje jen jeden směr a XML nemá žádné oficiální mapování do JSON – všechno stojí na konvenci.

Středně pokročilý~12 min čteníPublikováno 2026-10-30Aktualizováno 2026-10-30
Titulní obrázek článku Hranice převodu JSON ↔ YAML a XML

Stručně: používejte JSON jako zprostředkující formát: zdroj nejprve parsujte do datového modelu a poté serializujte do cíle; před převodem rozhodněte, zda musí přežít komentáře, atributy a jmenné prostory XML a číselné či booleovské typy.

Zda je převodní pipeline použitelná, nezávisí na tom, jak hezký je výstup, ale na tom, zda si uvědomujete, kolik toho zahodila.

1. JSON a YAML: jednostranné zahrnutí

Specifikace YAML 1.2 to říká přímo: JSON je podmnožina YAML. Každý platný JSON je tedy platný YAML:

{"name": "json", "tags": ["a", "b"], "count": 3}

Tento úryvek je zároveň JSON i YAML v proudovém stylu. Opak neplatí.

Vlastnost JSON YAML 1.2
Komentáře ✗ ✓
Kotvy a aliasy ✗ ✓
Více dokumentů (---) ✗ ✓
Neřetězcové klíče ✗ ✓ (1: a, true: b)
Složené klíče ✗ ✓ (? [a, b])
Citlivost na odsazení ✗ ✓ (odsazení tabulátorem je odmítnuto)
Odvozování typů explicitní implicitní (0o17, 0x1F, .inf)
Čitelnost jednoho řádku dobrá špatná (dlouhý obsah se spoléhá na syntaxi skládání)

1.1 Odvozování typů je největší past

YAML parsuje některé hodnoty, které vypadají jako řetězce, do jiných typů:

zip: 01234        # řetězec nebo osmičkové celé číslo? jádrové schéma YAML 1.2 to považuje za řetězec
version: 1.10     # 1.1 (desetinné číslo); sémantika se ztratí
country: NO       # v YAML 1.2 řetězec; v YAML 1.1 boolean false
date: 2026-10-30  # některé implementace to parsují jako objekt data

Příklad s NO už leckoho spálil: s parserem YAML 1.1 (některé starší knihovny) se country: NO stane false. Protiopatření: každý identifikátor, který „vypadá jako číslo nebo boolean“, dejte do uvozovek, například version: "1.10".

1.2 Kotvy, aliasy a více dokumentů

defaults: &defaults
  retries: 3
  timeout: 30

serviceA:
  <<: *defaults
  host: a.example.com

---
serviceB:
  <<: *defaults
  host: b.example.com

Po expanzi kotev a převodu do JSON obvykle skončíte se dvěma duplikovanými konfiguračními objekty, nebo s jedním polem (více dokumentů se musí stát [{...}, {...}]). V obou případech se kotvy při zpětném převodu neobnoví – tato ztráta je nevyhnutelná.

1.3 Převod, který zachovává komentáře

Většina knihoven komentáře při převodu prostě zahodí. Když je potřebujete udržet, použijte Document API balíčku yaml:

import { parseDocument } from 'yaml';

const document = parseDocument(`
# Konfigurace služby
port: 8080
`);

document.set('port', 3000);
console.log(document.toString());
// # Konfigurace služby
// port: 3000

Test je jednoduchý: pokud bude tento soubor lidmi znovu a znovu upravován, neberte cestu „parse → objekt → serializace“.

1.4 Jak ověřit konzistenci obousměrného převodu

/**
 * Ověří konzistenci obousměrného převodu JSON → YAML → JSON.
 * @param sourceValue Původní hodnota JSON
 * @param stringify Funkce pro serializaci YAML
 * @param parse Funkce pro parsování YAML
 * @returns Zda jsou oba výsledky přesně shodné
 */
function isRoundTripStable(
  sourceValue: unknown,
  stringify: (input: unknown) => string,
  parse: (input: string) => unknown,
): boolean {
  const yamlText = stringify(sourceValue);
  const restored = parse(yamlText);
  return JSON.stringify(restored) === JSON.stringify(sourceValue);
}

Spustit ho na skutečných datech má větší cenu než desetkrát číst dokumentaci. Zajistěte, aby sada vzorků pokrývala: null, prázdný řetězec, prázdné pole, "00", "1e5", zápornou nulu, celá čísla větší než 2^53 a dlouhé řetězce obsahující zalomení řádku.

2. JSON a XML: žádné standardní mapování neexistuje

XML je mnohem starší než JSON a má podstatně silnější strukturální možnosti (atributy, jmenné prostory, smíšený obsah, DTD). Mezi oběma formáty neexistuje žádná oficiální specifikace mapování; každý nástroj dělá totéž: zvolí konvenci a pak se snaží moc neztratit.

2.1 Běžné konvence

Konvence Reprezentace Příklad
Prvek → klíč objektu Stejnojmenný prvek se stane polem <a>1</a> → {"a": "1"}
Atribut → prefix @ @name <a id="1"/> → {"a": {"@id": "1"}}
Text → #text Když existuje atribut i text <a id="1">hi</a> → {"a": {"@id": "1", "#text": "hi"}}
Opakovaný prvek → pole Dva a více výskytů se stanou polem <i>1</i><i>2</i> → {"i": ["1","2"]}
Jmenný prostor → prefix ns:tag <ns:tag/> → {"ns:tag": ...}
<order id="A1001">
  <item sku="X1" qty="2">笔记本</item>
  <item sku="X2" qty="1">钢笔</item>
</order>
{
  "order": {
    "@id": "A1001",
    "item": [
      { "@sku": "X1", "@qty": "2", "#text": "笔记本" },
      { "@sku": "X2", "@qty": "1", "#text": "钢笔" }
    ]
  }
}

2.2 Pět nevyhnutelných ztrát

  1. Pořadí prvků: objekty JSON jsou neuspořádané, zatímco XML je uspořádaná posloupnost prvků;
  2. Atributy vs. podřízené prvky: v XML nesou odlišnou sémantiku, ale v JSON se obojí stane obyčejnými poli;
  3. Smíšený obsah: struktury jako <p>你好 <b>世界</b> 再见</p> nelze vyjádřit prostým objektem;
  4. Deklarace jmenných prostorů: xmlns je koncept rozsahu platnosti; po zploštění do polí je rozsah pryč;
  5. CDATA a entity: <![CDATA[...]]> a &amp; nejsou v JSON ničím víc než textem.

2.3 Dilema „jeden prvek, nebo pole“

<list><item>1</item></list>

Při jediném item vrátí xml2js ve výchozím nastavení objekt a pole vrátí až od dvou výskytů. Výsledkem je, že frontendový kód musí psát Array.isArray(x) ? x : [x].

Protiopatření: při parsování zapněte volbu „vždy pole“, nebo pole deklarujte jako typ pole podle schématu.

import { parseStringPromise } from 'xml2js';

const parsed = await parseStringPromise(xmlText, {
  explicitArray: true,   // vrátit pole i pro jediný prvek
  trim: true,
  explicitRoot: false,
});

2.4 Bezpečnostní připomenutí

Před parsováním nedůvěryhodného XML musíte vypnout externí entity, jinak můžete spustit XXE (čtení lokálních souborů, skenování vnitřní sítě):

// V ekosystému Node se DTD a externí entity obvykle vypínají pomocí voleb parseru
const parserOptions = { doctype: false, externalEntities: false };

Převod XML → JSON je jen první vrstva; převod neodstraňuje útočnou plochu, kterou XML přináší.

3. Kam který ze tří formátů patří

Scénář Doporučený formát Důvod
Veřejná HTTP API JSON Nativně podporovaný prohlížeči i každým jazykem
Ručně udržovaná konfigurace YAML Komentáře, odsazení, čitelnost
Dokumenty vyžadující silné schéma a jmenné prostory (SOAP, Office Open XML, SVG) XML Strukturální možnosti a existující ekosystém
Interakce s provozními nástroji (K8s, CI) YAML Výchozí formát ekosystému
Persistence, cache, logy JSON / JSONL Univerzální a bez závislostí

4. Poznámky k implementaci

import { stringify as toYaml } from 'yaml';

/**
 * Převede hodnotu JSON na text YAML a přitom ponechá čínské znaky neescapované.
 * @param value Hodnota JSON k převodu
 * @returns Text YAML
 */
function jsonToYaml(value: unknown): string {
  return toYaml(value, {
    indent: 2,
    lineWidth: 0,      // vypnout automatické zalamování, aby se dlouhé řetězce nelámaly
    defaultStringType: 'QUOTE_DOUBLE',
  });
}

Několik praktických voleb:

  • lineWidth: 0 vypne automatické zalamování; jinak se dlouhá URL láme do více řádků a špatně se čte;
  • citování všeho dvojitými uvozovkami zabrání chybnému čtení hodnot jako NO a 1.10;
  • u dat s citlivou číselnou přesností převeďte hodnoty na řetězce ještě před serializací.

Pro směr XML pevně stanovte jednu mapovací funkci a „prefix atributu“, „název textového klíče“ a „strategii polí“ dejte do jejího podpisu, místo abyste je rozptylovali kolem:

type XmlMappingOptions = {
  attributePrefix: string;
  textKey: string;
  alwaysArray: boolean;
};

const defaultMapping: XmlMappingOptions = {
  attributePrefix: '@',
  textKey: '#text',
  alwaysArray: false,
};

5. Kontrolní seznam

  • [ ] Každý identifikátor v YAML, který „vypadá jako číslo/boolean“, je v uvozovkách;
  • [ ] Sada validačních vzorků pro JSON → YAML → JSON je definována a pokryta testy;
  • [ ] Když se komentáře musí zachovat, používá se Document API, nikoli obousměrný převod přes objekt;
  • [ ] Konvence mapování XML je zapsaná a tým sdílí jednu sadu parametrů;
  • [ ] Při parsování nedůvěryhodného XML jsou DTD a externí entity vypnuté;
  • [ ] Počet bajtů a polí se před převodem a po něm porovnává a každá anomálie spustí alert.

Časté dotazy

Jak mám volit směr převodu mezi JSON, YAML a XML?

Preferujte JSON jako zprostředkující formát: nejprve parsujte YAML a XML do datového modelu a poté serializujte z tohoto modelu, místo abyste přepisovali text. Když musí komentáře přežít, použijte Document API YAML a jednu konvenci mapování XML pevně stanovte dřív, než budete potřebovat atributy nebo jmenné prostory.

Proč převod XML do JSON ztrácí atributy a jmenné prostory?

JSON nemá koncept atributů ani jmenných prostorů, takže atributy XML, prefixy a URI jmenných prostorů je nutné složit do obyčejných klíčů, obvykle s prefixem @ nebo uzlem #text. Jakmile se pravidla mapování rozcházejí, stejné XML produkuje různý JSON a nelze ho obousměrně převést.

Mám udržovat JSON, YAML a XML v dlouhodobé obousměrné synchronizaci?

Ne. Komentáře, kotvy, atributy XML a jmenné prostory jsou mezi formáty ztrátové a obousměrná synchronizace neustále hromadí rozdíly. Zvolte jeden zdrojový formát a ostatní považujte za jednorázové exporty nebo dočasné náhledy.

Zdroje

Související články

Převod JSON na CSV a tabulková data a zpět

CSV je dvourozměrné, JSON má tvar stromu. Obtížná část převodu není kód – je to rozhodnutí předem, jak se zplošťují pole a jak se zachovávají typy.

Začátečník~10 min čteníAktualizováno 2026-10-30

Správa JSON pro konfiguraci, fixtures a lokální data

Konfigurace musí být vrstvená a validovaná; fixtures musí být deterministické, čitelné a diffovatelné. Pokud se tyto dva druhy souborů spravují špatně, náklady na diagnostiku zůstávají dlouho vysoké.

Začátečník~10 min čteníAktualizováno 2026-10-30

JSON na YAML v příkazové řádce: čtyři pasti jednoho příkazu yq

Nejčastěji kopírovaný příkaz z návodů, yq -P input.json > output.yaml, na yq v4 pořád vydává JSON. Článek měří yq v4.44.6, PyYAML 6.0.3 a js-yaml na vzorku 2.39 MB, vysvětluje, proč formát výstupu určuje přípona vstupu, a dává správné zápisy pro dávkový převod, uvozovky, odsazení a přesnost velkých celých čísel.

Středně pokročilý~9 min čteníAktualizováno 2026-11-03