JSON Toolkit

I confini della conversione JSON ↔ YAML e XML

In sintesi: L'affermazione che JSON è un sottoinsieme di YAML garantisce una sola direzione, e XML non ha alcuna mappatura JSON ufficiale — tutto si basa sulla convenzione.

Intermedio~12 min di letturaPubblicato il 2026-10-30Aggiornato il 2026-10-30
Copertina dei confini della conversione JSON ↔ YAML e XML

In sintesi: usa JSON come formato intermedio: analizza la sorgente in un modello di dati, poi serializza verso la destinazione; prima di convertire, decidi se commenti, attributi e namespace XML e tipi numerici o booleani devono sopravvivere.

Se una pipeline di conversione è utilizzabile non dipende da quanto è bello l'output, ma da quanto sei consapevole di ciò che ha buttato via.

1. JSON e YAML: contenimento unidirezionale

La specifica YAML 1.2 lo dice chiaramente: JSON è un sottoinsieme di YAML. Cioè, qualsiasi JSON valido è YAML valido:

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

Questo frammento è sia JSON sia YAML in stile flow. Il contrario non vale.

Funzionalità JSON YAML 1.2
Commenti ✗ ✓
Anchor e alias ✗ ✓
Documenti multipli (---) ✗ ✓
Chiavi non stringa ✗ ✓ (1: a, true: b)
Chiavi complesse ✗ ✓ (? [a, b])
Sensibile all'indentazione ✗ ✓ (l'indentazione con tab viene rifiutata)
Inferenza dei tipi esplicita implicita (0o17, 0x1F, .inf)
Leggibilità su una riga buona scarsa (i contenuti lunghi si affidano alla sintassi di folding)

1.1 L'inferenza dei tipi è la trappola più grande

YAML interpreta alcuni valori che sembrano stringhe come altri tipi:

zip: 01234        # string or octal integer? the YAML 1.2 core schema treats it as a string
version: 1.10     # 1.1 (a float); the semantics are lost
country: NO       # a string in YAML 1.2; boolean false in YAML 1.1
date: 2026-10-30  # some implementations parse it as a date object

L'esempio di NO ha bruciato parecchia gente: con un parser YAML 1.1 (alcune librerie più vecchie), country: NO diventa false. Contromisura: metti tra virgolette ogni identificatore che "sembra un numero o un booleano", come in version: "1.10".

1.2 Anchor, alias e documenti multipli

defaults: &defaults
  retries: 3
  timeout: 30

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

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

Dopo aver espanso gli anchor e aver convertito in JSON si ottengono di solito due oggetti di configurazione duplicati, oppure un singolo array (i documenti multipli devono diventare [{...}, {...}]). In ogni caso, gli anchor non vengono ripristinati nella conversione inversa — quella perdita è inevitabile.

1.3 Conversione che preserva i commenti

La maggior parte delle librerie elimina semplicemente i commenti durante la conversione. Quando devi conservarli, usa l'API Document del pacchetto yaml:

import { parseDocument } from 'yaml';

const document = parseDocument(`
# Service configuration
port: 8080
`);

document.set('port', 3000);
console.log(document.toString());
// # Service configuration
// port: 3000

Il test è semplice: se questo file verrà modificato dalle persone più e più volte, non prendere la strada "parse → object → serialize".

1.4 Come verificare la coerenza del round-trip

/**
 * Verifies round-trip consistency for JSON → YAML → JSON.
 * @param sourceValue Original JSON value
 * @param stringify YAML serialization function
 * @param parse YAML parsing function
 * @returns Whether the two results are exactly equal
 */
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);
}

Eseguirlo su dati reali vale più che leggere la documentazione dieci volte. Assicurati che il tuo set di esempi copra: null, la stringa vuota, l'array vuoto, "00", "1e5", lo zero negativo, gli interi più grandi di 2^53 e le stringhe lunghe che contengono a capo.

2. JSON e XML: non esiste una mappatura standard

XML precede JSON di molto e ha capacità strutturali molto più forti (attributi, namespace, contenuto misto, DTD). Tra i due non esiste una specifica di mappatura ufficiale; ogni strumento fa la stessa cosa: sceglie una convenzione, poi cerca di non perdere troppo.

2.1 Convenzioni comuni

Convenzione Rappresentazione Esempio
Elemento → chiave dell'oggetto Un elemento con lo stesso nome diventa un campo <a>1</a> → {"a": "1"}
Attributo → prefisso @ @name <a id="1"/> → {"a": {"@id": "1"}}
Testo → #text Quando ci sono sia un attributo sia del testo <a id="1">hi</a> → {"a": {"@id": "1", "#text": "hi"}}
Elemento ripetuto → array Due o più occorrenze diventano un array <i>1</i><i>2</i> → {"i": ["1","2"]}
Namespace → prefisso 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 Cinque perdite inevitabili

  1. Ordine degli elementi: gli oggetti JSON non sono ordinati, mentre XML è una sequenza ordinata di elementi;
  2. Attributi vs elementi figli: in XML hanno semantica diversa, ma in JSON diventano entrambi campi semplici;
  3. Contenuto misto: strutture come <p>你好 <b>世界</b> 再见</p> non possono essere espresse con un oggetto semplice;
  4. Dichiarazioni di namespace: xmlns è un concetto di scope; una volta appiattito in campi, lo scope è perso;
  5. CDATA ed entità: <![CDATA[...]]> e &amp; in JSON non sono altro che testo.

2.3 Il dilemma di "un elemento o un array"

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

Con un singolo item, xml2js restituisce un oggetto per impostazione predefinita e restituisce un array solo quando ce ne sono due. Di conseguenza il codice frontend deve scrivere Array.isArray(x) ? x : [x].

Contromisura: attiva l'opzione "sempre array" durante il parsing, oppure dichiara il campo come tipo array in base a uno schema.

import { parseStringPromise } from 'xml2js';

const parsed = await parseStringPromise(xmlText, {
  explicitArray: true,   // return an array even for a single element
  trim: true,
  explicitRoot: false,
});

2.4 Promemoria di sicurezza

Prima di analizzare XML non fidato devi disattivare le entità esterne, altrimenti puoi innescare XXE (lettura di file locali, sondaggio di reti interne):

// In the Node ecosystem, DTDs and external entities are usually disabled through parser options
const parserOptions = { doctype: false, externalEntities: false };

XML → JSON è solo il primo strato di conversione; convertire non elimina la superficie d'attacco che XML porta con sé.

3. Dove si colloca ciascuno dei tre formati

Scenario Formato consigliato Motivo
API HTTP pubbliche JSON Supportato nativamente dai browser e da ogni linguaggio
Configurazione mantenuta a mano YAML Commenti, indentazione, leggibilità
Documenti che richiedono uno schema forte e namespace (SOAP, Office Open XML, SVG) XML Capacità strutturali e l'ecosistema esistente
Interazione con strumenti operativi (K8s, CI) YAML Il valore predefinito dell'ecosistema
Persistenza, cache, log JSON / JSONL Universale e senza dipendenze

4. Note di implementazione

import { stringify as toYaml } from 'yaml';

/**
 * Converts a JSON value to YAML text while keeping Chinese characters unescaped.
 * @param value The JSON value to convert
 * @returns The YAML text
 */
function jsonToYaml(value: unknown): string {
  return toYaml(value, {
    indent: 2,
    lineWidth: 0,      // disable automatic wrapping so long strings are not split
    defaultStringType: 'QUOTE_DOUBLE',
  });
}

Alcune opzioni pratiche:

  • lineWidth: 0 disattiva l'a capo automatico; altrimenti gli URL lunghi vengono spezzati su più righe e diventano difficili da leggere;
  • racchiudere tutto tra virgolette doppie evita che valori come NO e 1.10 vengano fraintesi;
  • per i dati con precisione numerica sensibile, converti in stringhe prima di serializzare.

Per la direzione XML, fissa un'unica funzione di mappatura e metti "prefisso degli attributi", "nome della chiave di testo" e "strategia per gli array" nella sua firma invece di spargerli in giro:

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

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

5. Checklist

  • [ ] Ogni identificatore YAML che "sembra un numero o un booleano" è tra virgolette;
  • [ ] È definito un set di esempi di validazione per JSON → YAML → JSON, coperto dai test;
  • [ ] Quando i commenti devono essere preservati, si usa l'API Document invece di un round trip sugli oggetti;
  • [ ] La convenzione di mappatura XML è messa per iscritto e il team condivide un unico set di parametri;
  • [ ] DTD ed entità esterne sono disattivati durante il parsing di XML non fidato;
  • [ ] Si confrontano conteggi di byte e di campi prima e dopo la conversione, e ogni anomalia genera un avviso.

FAQ

Come scelgo la direzione di conversione tra JSON, YAML e XML?

Preferisci JSON come formato intermedio: analizza prima YAML e XML in un modello di dati, poi serializza da quel modello invece di riscrivere il testo. Usa l'API Document di YAML quando i commenti devono sopravvivere, e fissa una convenzione di mappatura XML prima di aver bisogno di attributi o namespace.

Perché la conversione da XML a JSON perde attributi e namespace?

JSON non ha il concetto di attributi o namespace, quindi gli attributi XML, i prefissi e gli URI di namespace devono essere ripiegati in chiavi ordinarie, di solito con un prefisso @ o un nodo #text. Una volta che le regole di mappatura divergono, lo stesso XML produce JSON diversi e non può fare round-trip.

Devo mantenere JSON, YAML e XML sincronizzati a due vie nel tempo?

No. Commenti, anchor, attributi XML e namespace sono soggetti a perdita tra i formati, e la sincronizzazione a due vie accumula continuamente differenze. Scegli un formato sorgente e tratta gli altri come esportazioni una tantum o viste temporanee.

Riferimenti

Articoli correlati

Conversione tra JSON e CSV e dati tabellari

CSV è bidimensionale, JSON ha forma ad albero. La parte difficile della conversione non è il codice — è decidere in anticipo come appiattire gli array e come preservare i tipi.

Principiante~10 min di letturaAggiornato il 2026-10-30

Gestire JSON per configurazione, fixture e dati locali

La configurazione deve essere stratificata e validata; i fixture devono essere deterministici, leggibili e diffabili. Se questi due tipi di file vengono gestiti male, i costi di troubleshooting restano alti a lungo.

Principiante~10 min di letturaAggiornato il 2026-10-30

Da JSON a YAML sulla riga di comando: le quattro trappole dietro un comando yq

Il comando più ricopiato delle guide, yq -P input.json > output.yaml, produce ancora JSON su yq v4. Questo articolo misura yq v4.44.6, PyYAML 6.0.3 e js-yaml su un campione da 2.39 MB, spiega perché l'estensione dell'input decide il formato di output e mostra le scritture corrette per conversione batch, virgolette, indentazione e precisione dei grandi interi.

Intermedio~9 min di letturaAggiornato il 2026-11-03