Convertitore da JSON a YAML

Converte JSON in YAML e spiega ogni virgoletta che aggiunge: le stringhe che senza di essa diventerebbero booleani, numeri o date in silenzio.

Input
YAML
name: deploy
country: 'NO'
startsAt: '12:30'
mode: '0755'
version: '1.10'
released: '2024-01-30'
enabled: 'yes'
script: |-
  set -e
  npm run build
  npm test
replicas: 3
tags:
  - web
  - edge
Perché ogni stringa è fra virgolette

Valori fra virgolette: 6. Richieste solo da YAML 1.1: 4. Cambia lo schema qui sopra per vedere la differenza.

  • countrysolo 1.1

    «NO» verrebbe letto come il booleano false.

  • startsAtsolo 1.1

    «12:30» verrebbe letto in base 60 come 750.

  • mode

    «0755» ha uno zero iniziale, quindi verrebbe letto come il numero 493.

  • version

    «1.10» verrebbe letto come il numero 1.1.

  • releasedsolo 1.1

    «2024-01-30» verrebbe letto come una data e non come testo.

  • enabledsolo 1.1

    «yes» verrebbe letto come il booleano true.

Che cosa fa questo strumento

Converte un documento JSON in YAML e poi ti dice perché ciascuna stringa è finita fra virgolette. Quella seconda parte è la ragione per cui lo strumento esiste: ogni altro convertitore restituisce l’output e ti lascia scoprire più tardi che uno dei tuoi valori non è più una stringa.

La conversione va in un solo verso. Leggere YAML è un problema assai più grande che scriverlo, e un analizzatore YAML parzialmente corretto è peggio di nessuno: accetta il tuo file e restituisce dati sbagliati senza lamentarsi. Emettere è un problema delimitato, ed è il verso coperto qui.

Perché un convertitore ha bisogno di opinioni

JSON dice di che tipo è ogni cosa. Una stringa ha le virgolette, un numero no, e non esiste una terza possibilità. YAML invece decide il tipo di un valore non quotato guardandone la forma: se corrisponde al modello di un booleano è un booleano, se corrisponde a un numero è un numero, e solo se non corrisponde a nulla resta testo.

È questo che rende YAML piacevole da scrivere a mano e che fa della conversione una questione di giudizio. Ogni stringa dell’input va confrontata con ogni modello che YAML risolve, e messa fra virgolette se ne incontra uno. Sbaglia dal lato prudente e l’output è rumoroso; sbaglia dall’altro e un valore cambia tipo in silenzio.

Il problema della Norvegia e i suoi parenti

Il caso più noto è un elenco di codici paese. La Norvegia è NO, e in YAML 1.1 il token non quotato NO è il booleano false. Un file di configurazione che elenca paesi perde la Norvegia e guadagna un false, e da nessuna parte nulla segnala un errore.

Non è una regola strana isolata ma un’intera famiglia. YAML 1.1 legge y, Y, yes, no, on e off come booleani, in qualsiasi grafia, e così cattura un simbolo chimico, la posizione di un interruttore e la risposta a una domanda. E i risolutori numerici sono ancora più strani:

  • 12:30 è 750. YAML 1.1 legge cifre separate da due punti in base 60, quindi un’ora del giorno o una durata diventa un intero.
  • 0755 è 493. Uno zero iniziale significa ottale in YAML 1.1 — e in YAML 1.2 lo stesso testo è il decimale 755: le due versioni discordano su quale numero, non sul fatto che lo sia.
  • 1.10 è 1.1. Un numero di versione in due parti è un decimale, e lo zero finale sparisce. Una dipendenza fissata a 1.10 ora punta a 1.1.
  • 2024-01-30 è un oggetto data e non una stringa, perché YAML 1.1 ha un tipo marca temporale.
  • Una stringa vuota è null, come lo sono le parole nude null, Null, NULL e la tilde.

Nessuno di questi è un difetto di YAML. Sono i risolutori che fanno esattamente ciò che promettono, su un testo che per caso corrisponde. L’unica difesa è mettere fra virgolette tutto ciò che corrisponde, che è quel che fa questo strumento e quel che il pannello dei riscontri rende conto riga per riga.

Due versioni, e perché quella vecchia è predefinita

YAML 1.2 è arrivato nel 2009 e ha rimosso quasi tutti i risolutori sorprendenti. Il suo schema base tiene solo true e false come booleani, abbandona del tutto la base 60 e non ha un tipo marca temporale. Sotto 1.2, NO e 12:30 e 2024-01-30 sono semplicemente stringhe.

L’insidia è che cosa legga davvero il tuo file. PyYAML implementa YAML 1.1, e PyYAML sta dietro a una quantità enorme di strumenti: Ansible, vecchi client Kubernetes, innumerevoli script. yaml.v3 di Go e l’attuale js-yaml seguono 1.2. Lo stesso documento può quindi essere letto in due modi diversi a seconda di chi lo apre, e l’unico output sicuro ovunque è quello quotato per 1.1.

È questa la predefinita qui. Passare a 1.2 non nasconde nulla: riemette con i risolutori più recenti e il pannello dei riscontri si accorcia, così vedi con precisione quali virgolette c’erano per lo schema vecchio. Quelle che restano sono quelle di cui ogni analizzatore ha bisogno.

Stringhe che rompono la sintassi, non il tipo

Un secondo gruppo di stringhe va quotato per un motivo diverso: non perché YAML le leggerebbe come un altro tipo, ma perché non si analizzerebbero affatto come testo.

  • Due punti seguiti da uno spazio chiudono una chiave. «note: time: now» verrebbe letto come una chiave note il cui valore è una chiave time.
  • Uno spazio seguito da un cancelletto apre un commento, quindi tutto ciò che segue sparisce.
  • Un -, ?, :, [, ], {, }, #, &, *, !, |, >, %, @ o accento grave iniziale è un carattere indicatore e ha un significato strutturale.
  • Uno spazio iniziale o finale non viene conservato da un valore non quotato, quindi « x » torna come «x».
  • Una tabulazione ovunque nel valore viene respinta del tutto: PyYAML rifiuta l’intero documento invece di leggerlo male, quindi questo caso fallisce rumorosamente.

Gli apici singoli si usano ovunque bastino, perché hanno esattamente una regola di escape — un apostrofo si scrive due volte — e si leggono meglio degli escape con barra rovesciata che portano le virgolette doppie. Queste ultime restano riservate a ciò che ha davvero bisogno di escape: caratteri di controllo, tabulazioni e stringhe su più righe che non possono usare un blocco.

Stringhe su più righe e l’indicatore di taglio

Una stringa che contiene ritorni a capo — uno script, un certificato, un blocco di prosa — è di solito il motivo per cui si vuole YAML in primo luogo. JSON può scriverla solo con escape barra-n su un’unica riga lunghissima; YAML ha lo scalare a blocco letterale, introdotto da una barra verticale, dove il testo compare rientrato e leggibile sotto.

La sottigliezza sta in che cosa accade ai ritorni a capo finali, e lo governa l’indicatore di taglio:

  • Una barra verticale nuda taglia: per quanti ritorni finali abbia il blocco, il valore ne tiene esattamente uno.
  • Una barra verticale seguita da un meno elimina: il valore non ne tiene nessuno.
  • Una barra verticale seguita da un più conserva: il valore li tiene tutti.

Questo strumento sceglie l’indicatore dalla stringa che ha ricevuto, così il valore sopravvive esattamente al viaggio di andata e ritorno. Vale la pena saperlo perché la predefinita — la barra nuda — è quella che si scrive a mano, e normalizza in silenzio una stringa che finiva con due ritorni a capo o con nessuno.

Uno scalare a blocco non può portare tutto, e dove non può, l’output ripiega sulle virgolette doppie e il pannello dei riscontri dice perché. Un ritorno a capo di tipo CR non sopravvive, perché gli scalari a blocco normalizzano le interruzioni di riga. Una prima riga che inizia con uno spazio verrebbe letta come rientro aggiuntivo e tolta. E una riga che finisce con uno spazio è conservata dalla specifica, ma è invisibile a schermo e la maggior parte degli editor la elimina al salvataggio: quotarla è quindi più sicuro — è una decisione e non un limite, e viene segnalata come tale.

Più di un documento

YAML ha qualcosa che JSON non ha: un file può contenere un flusso di documenti separati da tre trattini. È il formato di un manifesto Kubernetes, ed è il motivo per cui un array JSON tanto spesso deve diventare qualcosa di diverso da una sequenza YAML.

L’interruttore qui emette ogni elemento di un array di primo livello come documento a sé. E quando l’input non è affatto un unico valore JSON ma ogni riga si analizza da sola, viene letto come NDJSON — il formato delimitato da righe in cui arrivano log ed esportazioni di API — e ogni riga diventa un documento. Quella lettura è una supposizione, quindi viene segnalata sopra l’output invece che fatta in silenzio.

Il ripiego si applica solo quando l’intero input fallisce l’analisi e ogni riga riesce, cosa che un documento semplicemente malformato non farà. Un errore di sintassi resta un errore di sintassi, con la riga e la colonna in cui si è verificato.

Ciò che la conversione non può conservare

Due cose si perdono prima che questo strumento veda i tuoi dati, entrambe nell’analisi JSON stessa, e conviene sapere quali.

Chiavi duplicate. JSON permette a un oggetto di elencare la stessa chiave due volte e la maggior parte degli analizzatori tiene l’ultima in silenzio. YAML vieta i duplicati del tutto, quindi l’output sarà valido, ma il valore precedente è già andato — e nessun convertitore può segnalare ciò che non ha mai ricevuto.

Precisione degli interi. Un numero JSON maggiore di circa novemila miliardi di milioni non sopravvive all’analisi in un double, quindi un identificatore come 12345678901234567890 torna arrotondato. Non è un problema di YAML né uno introdotto da questo strumento; accade in ogni analizzatore JSON del linguaggio. Se un identificatore grande conta, va messo in una stringa da entrambe le parti.

Note sull’output

Il rientro è a spazi, sempre, perché YAML vieta del tutto le tabulazioni per rientrare: è una delle poche cose su cui il formato è severo. Due spazi sono la convenzione; quattro sono offerti perché alcuni stili aziendali li vogliono.

Le sequenze sono rientrate sotto la loro chiave. Sia questa forma sia quella non rientrata sono YAML valido e significano la stessa cosa; la rientrata è quella che scrive la maggior parte delle persone e che la maggior parte degli editor ripiega correttamente.

Un array o un oggetto vuoto si scrive in stile a flusso come una coppia di parentesi, perché lo stile a blocco non ha modo di esprimere il vuoto: non c’è nulla da scrivere sulle righe seguenti.

L’output termina con un ritorno a capo, e questo è funzionale e non estetico. Il taglio di uno scalare a blocco si misura sull’interruzione di riga che lo segue, quindi un blocco tagliato proprio in fondo a un file senza ritorno finale perde il ritorno che avrebbe dovuto conservare.

I manifesti Kubernetes e i campi che devono restare stringhe

Kubernetes legge un manifesto in entrambi i formati. La sua stessa documentazione chiama YAML la convenzione e cita JSON come alternativa, e kubectl converte un manifesto in JSON, o in un’altra serializzazione che l’API accetta, nel momento in cui fa la richiesta: convertire non riguarda dunque quello che il cluster accetterà. Riguarda il file che ti resta: YAML è ciò che legge chi revisiona, ciò in cui un diff di una pull request è leggibile, e il solo dei due capace di portare un commento. Il JSON arriva di solito da kubectl get -o json, da un modello o da un’API che restituisce oggetti.

  • Un file, più oggetti. I manifesti possono essere raccolti in un unico file separati da tre trattini, e la documentazione dice esplicitamente che vengono creati nell’ordine in cui appaiono — ed è per questo che un Service si scrive di solito sopra il Deployment che lo riempie. L’interruttore che emette ogni elemento di un array di primo livello come documento a sé è ciò che trasforma un elenco di oggetti JSON in un file così.
  • Le voci di ambiente di un contenitore sono due campi di tipo stringa. Il riferimento dell’API dichiara stringhe sia name sia value, quindi un valore JSON pari a "true" deve uscire con le sue virgolette: senza di esse è un booleano, e un booleano non è il tipo che quel campo è dichiarato a contenere.
  • Una porta di contenitore è dichiarata intera, e sta a poche righe da quelle stringhe. I due chiedono il trattamento opposto, e il JSON porta già la distinzione: un numero diventa un numero nudo, e una stringa viene quotata soltanto dove YAML smetterebbe di leggerla come tale.
  • Le etichette e le annotazioni sono mappe da stringa a stringa. È lì che il problema norvegese atterra dentro un manifesto: un’etichetta il cui valore sia NO, on oppure off è un booleano per un analizzatore YAML 1.1, e un valore di 1.10 è un decimale che perde lo zero finale.

Tre voci di ambiente, date come JSON con tutti i valori in stringa, si convertono così:

env:
  - name: DEBUG
    value: 'true'
  - name: REPLICAS
    value: '3'
  - name: COUNTRY
    value: 'NO'

Tutte e tre sono quotate, e il pannello dei riscontri nomina tutte e tre con il valore in cui ciascuna si sarebbe trasformata: true è un booleano, 3 è un numero e NO è il booleano false. Solo l’ultima dipende dalla versione: porta lo schema a 1.2 e le sue virgolette cadono, perché 1.2 non legge NO come nulla che non sia testo. Le altre due mantengono le proprie in entrambe.

Docker Compose, dove il riferimento del formato stesso avverte su YAML

Un file Compose è YAML, e il riferimento che Docker gli dedica porta due avvertenze sull’analisi di YAML. Che la documentazione di un prodotto indichi come pericolo il proprio formato di serializzazione è insolito, e le due avvertenze riguardano esattamente ciò per cui questo strumento esiste: un valore pensato come testo che un analizzatore legge come altro.

  • Le porte. Il riferimento dice che una corrispondenza HOST:CONTAINER va sempre data come stringa quotata, per evitare un conflitto con il decimale in base 60 di YAML. Senza virgolette, 22:22 è l’intero 1342.
  • I valori di ambiente. Il riferimento chiede che true, false, yes e no siano racchiusi tra virgolette perché l’analizzatore non li converta. Due dei quattro sono booleani in entrambe le versioni di YAML e due — yes e no — nella sola 1.1, ed è per questo che il pannello dei riscontri li segna in modo diverso.
  • La regola della base 60 raggiunge solo una corrispondenza il cui numero dopo i due punti è minore di sessanta, perché tanto copre una singola cifra in base 60. Perciò 22:22 qui è quotato e 8080:80 resta nudo, e la differenza è la regola e non un giudizio su quali porte contino.

Un servizio le cui porte e i cui valori di ambiente nel JSON sono tutti stringhe si converte in questo:

services:
  proxy:
    image: nginx
    ports:
      - '22:22'
      - 8080:80
    environment:
      TLS_ENABLED: 'no'
      DEBUG: 'true'

È l’output che il riferimento chiede, e lo produce lo schema predefinito. È anche la ragione più chiara per non toccare lo schema: passa a 1.2 e la corrispondenza di porte e il no perdono le virgolette mentre il true conserva le sue, perché 1.2 ha abbandonato la base 60 e tiene come booleani soltanto true e false. Un analizzatore che implementa 1.2 legge ancora il risultato correttamente, ma il consiglio di Docker è scritto senza alcuna condizione del genere, e seguirlo costa due paia di virgolette.

Domande frequenti

JSON è già YAML valido?
Sotto YAML 1.2 sì: la specifica lo dice esplicitamente e un analizzatore 1.2 legge un file JSON direttamente. In pratica serve a poco, perché il motivo per convertire è la leggibilità — commenti, scalari a blocco, niente graffe — e incollare JSON in un file YAML non te ne dà nessuna. Sotto YAML 1.1 non è del tutto vero, il che è un motivo in più per distinguere le due versioni.
Perché la mia stringa ha ricevuto virgolette di cui non sembra avere bisogno?
Quasi certamente ne ha bisogno. YAML tipizza un valore non quotato confrontando modelli, quindi NO, yes, off, 12:30, 0755, 1.10, 2024-01-30 e la stringa vuota smettono tutti di essere stringhe. Il pannello dei riscontri nomina ciascuno e mostra il valore in cui si sarebbe trasformato, così l’affermazione si verifica invece di essere creduta. Se punti a un analizzatore YAML 1.2, cambiare schema toglie quelle che servono solo a 1.1.
Qual è qui la differenza fra YAML 1.1 e 1.2?
1.2 ha abbandonato i risolutori che causano quasi tutte le sorprese: yes/no/on/off non sono più booleani, la base 60 è sparita e non esiste un tipo marca temporale. PyYAML implementa 1.1 ed è ancora ovunque, quindi l’output prudente è quello predefinito; l’impostazione 1.2 c’è per quando sai che cosa leggerà il file.
Può riconvertire YAML in JSON?
No, di proposito. Un lettore YAML ha bisogno di àncore, alias, tag, chiavi di fusione, cinque stili di scalare e due versioni di schema, e sbagliare finemente su uno qualsiasi significa accettare un file e restituire dati diversi da quelli che conteneva. Quel fallimento è silenzioso, il che lo rende peggiore che non offrire affatto la funzione.
Come ottengo un file multidocumento in stile Kubernetes?
Attiva l’interruttore che emette ogni elemento di un array di primo livello come documento a sé, e l’array diventa documenti separati da tre trattini. Se il tuo input è NDJSON — un oggetto JSON per riga, come spesso arrivano log ed esportazioni di API — viene rilevato automaticamente e segnalato sopra l’output.
Perché non ci sono commenti nell’output?
Perché non ce n’erano nell’input. I commenti sono la cosa principale che YAML ha e JSON no, e un convertitore non può inventarli. Vale la pena ricordarlo anche nell’altro verso: se fai passare un file YAML per JSON e ritorno, ogni suo commento è sparito.
Qualcosa di ciò che incollo viene inviato a un server?
No. L’analisi e la conversione avvengono interamente nel tuo browser; nulla viene caricato o registrato, e funziona senza connessione di rete.
Come converto l’output JSON di kubectl in un manifesto YAML?
Incollalo e leggi lo YAML. Kubernetes accetta entrambi i formati — la sua documentazione chiama YAML la convenzione e JSON l’alternativa — quindi la ragione per convertire sta nel file che ti resta e non in ciò che il cluster accetterà. Da controllare sono le virgolette: un manifesto è pieno di campi che l’API dichiara stringhe, tra cui i valori di ambiente e quelli di etichette e annotazioni, e sono proprio quelli a cui YAML cambierebbe il tipo. Se il JSON è un elenco di più oggetti, l’interruttore multidocumento ne fa un unico file.
Perché Docker Compose vuole le mie porte tra virgolette?
Perché per un analizzatore YAML 1.1 22:22 non è una coppia di numeri ma un solo numero in base 60: 1342. Il riferimento Compose di Docker dice proprio per questo che una corrispondenza HOST:CONTAINER dovrebbe essere sempre una stringa quotata, e la stessa pagina chiede di quotare anche true, false, yes e no dentro un blocco di ambiente. Entrambe le cose sono quello che questo strumento fa con lo schema predefinito, e il pannello dei riscontri dice da quale regola viene ciascuna coppia di virgolette. Una corrispondenza il cui numero dopo i due punti è sessanta o più, come 8080:80, sta fuori dalla regola della base 60 e resta nuda.
Quale versione di YAML conviene scegliere per Kubernetes o Docker Compose?
Quella predefinita, 1.1. Ogni coppia di virgolette che aggiunge è accettata anche da un analizzatore 1.2, quindi l’output prudente è sicuro in ogni caso, e le due avvertenze del riferimento Compose riguardano regole di 1.1: le corrispondenze di porte in base 60, e yes e no come booleani. L’impostazione 1.2 c’è per mostrare quali virgolette esistono solo per lo schema più vecchio; l’output le perde, che è il contrario di ciò che quelle avvertenze chiedono.

Strumenti correlati