Da YAML a JSON (e ritorno)
Incolla una configurazione e scegli il verso. Gli errori arrivano con la riga giusta, e la pagina ti dice quali valori un lettore YAML 1.1 leggerebbe in un altro modo: «no» che diventa false, «22:22» che diventa 1342.
Perché «no» diventa false: la trappola della Norvegia
YAML esiste in due versioni che si usano tutte e due. La 1.1 è del 2005 ed è quella di PyYAML, quindi di Python e di Ansible; la 1.2 è del 2009 ed è quella dei lettori più recenti, compreso quello di questa pagina. Il testo del file è lo stesso, ma certe parole scritte senza virgolette per le due versioni sono cose diverse.
L'esempio che ha dato il nome al problema è il codice della Norvegia: in un elenco di paesi NO per un lettore 1.1 è il booleano falso, e la Norvegia sparisce. Non è l'unico caso. yes, on e off sono booleani anche loro, e infatti la chiave on: dei workflow di GitHub Actions, letta con PyYAML, diventa true. 0755 è un numero ottale e vale 493. 22:22, la mappatura di una porta in un docker-compose, è un numero in base 60 e vale 1342. In YAML 1.2 sono tutti testo, tranne 0755 che diventa il numero 755.
Per questo la pagina non si limita a convertire: per ogni valore scritto senza virgolette chiede ai due lettori che cosa ci vedono, e se non sono d'accordo te lo dice con la riga, il valore di qui e quello dell'altra versione. Con il menu Leggi lo YAML come scegli quale lettore imitare. La lettura 1.1 è quella di PyYAML, carattere per carattere; la specifica 1.1 elenca fra i booleani anche y e n, ma PyYAML non lo fa e qui si segue PyYAML, perché è il lettore 1.1 che la gente ha davvero fra le mani. La cura, in tutti i casi, è la stessa: le virgolette.
Gli errori, con la riga giusta
È il motivo per cui quasi tutti aprono un convertitore: il programma dice che il file non va, e non dice dove. Qui ogni errore ha un nome, la riga e un estratto con la riga evidenziata, e il pulsante Vai alla riga la seleziona nel riquadro.
I casi più comuni hanno una spiegazione loro. Una tabulazione nel rientro, che YAML non accetta e che a occhio non si distingue dagli spazi (nell'estratto si vede come una freccia); e, in lettura 1.1, anche quella dopo i due punti o in fondo alla riga, che YAML 1.2 lascia passare e PyYAML no. Un rientro che non è allineato con le righe dello stesso livello. Un valore con i due punti seguiti da uno spazio, come titolo: Roma: guida, che YAML scambia per una chiave nuova. Un apostrofo dentro gli apici singoli, come in 'Non c'è niente', che chiude il testo a metà. Un valore senza virgolette che comincia con una chiocciola, come @types/node, o con una variabile di Ansible, come {{ app_version }}. Lo spazio che manca dopo i due punti. Una chiave ripetuta, che PyYAML prenderebbe senza dire niente tenendo l'ultima.
Il caso più cattivo è la virgoletta rimasta aperta: il lettore se ne accorge solo righe dopo, e segnala la riga sbagliata. Qui si va a cercare la riga dove la virgoletta o la parentesi si apre senza chiudersi, e si evidenzia quella. Sotto resta comunque il messaggio originale del lettore, per chi lo vuole.
Quello che JSON non sa dire, detto
Le date restano testo, esattamente come sono scritte, perché JSON non ha un tipo per le date; la pagina elenca le righe, perché PyYAML invece le trasformerebbe. Gli interi oltre 2^53, come un codice d'ordine di venti cifre, sono scritti nel JSON cifra per cifra, ma la pagina avverte che un programma JavaScript che li rilegge li arrotonda: 12345678901234567890 diventerebbe 12345678901234567000. I valori infinito e «non un numero» diventano null, e sono elencati. I numeri che cambiano forma sono segnalati a parte: 3.10 diventa 3.1, che è lo stesso numero ma non la stessa versione di Python.
I tag come !Ref e !Sub di CloudFormation o !reference di GitLab non esistono in JSON: il valore resta, il tag no, e la pagina elenca quali e dove. Più documenti separati da --- diventano un elenco. Le ancore e gli alias vengono espansi, e qui c'è un limite dichiarato: se l'espansione aggiunge più di 100.000 valori, la conversione si ferma. È la difesa contro l'attacco chiamato «billion laughs», dieci righe che espanse diventano un miliardo di valori e bloccano qualunque programma le legga fino in fondo.
Da JSON a YAML: le virgolette che servono davvero
Nel verso opposto il rischio è rovesciato. Un testo come "no", "010" o "12:30" nel JSON è chiaramente un testo; scritto nello YAML senza virgolette, il primo lettore 1.1 lo trasforma in un booleano o in un numero. Qui ogni testo che anche uno solo dei due lettori leggerebbe come altro viene messo tra virgolette, e la pagina ti dice quali sono.
Scegli il rientro, due o quattro spazi, oppure la forma compatta su una riga sola. Se il JSON è un elenco, puoi trasformarlo in più documenti YAML separati da ---, come si fa con i file di Kubernetes. E se il JSON non si legge, l'errore ha un nome anche qui: la virgola in fondo prima della parentesi, gli apici singoli, il commento, la chiave senza virgolette. Il lettore JSON è scritto apposta invece di usare quello del browser, che arrotonda gli interi grandi e che in ogni browser indica l'errore in un modo diverso. Per sistemare un JSON senza cambiare formato, rientrarlo o ordinarne le chiavi, c'è Formatta e valida JSON.
Come è stato provato
Il giudice non è questa pagina: è PyYAML, il lettore YAML di Python, usato in due modi. Così com'è dà la lettura 1.1; con le regole del Core Schema riscritte dal testo della specifica 1.2 dà la lettura 1.2. Su 500 documenti generati a caso, pieni delle trappole di sopra, con ancore, fusioni e più documenti, i valori della pagina devono coincidere con i suoi nelle due letture, e l'elenco delle righe segnalate deve essere esattamente quello delle righe su cui le due letture di PyYAML non sono d'accordo, né una in più né una in meno. Lo stesso vale per le tabulazioni: su 600 documenti con una tabulazione messa a caso, la lettura 1.1 della pagina accetta e rifiuta esattamente quelli che accetta e rifiuta PyYAML, e quando si ferma per la tabulazione indica la stessa riga e la stessa colonna.
Nell'altro verso, 400 strutture JSON generate a caso, scritte con tre rientri diversi, fanno il giro completo: dal JSON allo YAML e di nuovo al JSON, e alla fine devono tornare identiche. In mezzo lo YAML prodotto viene riletto da PyYAML nelle due versioni, e deve dare lo stesso dato del JSON di partenza. Il lettore JSON, infine, viene messo a confronto con il modulo json di Python su 1.200 testi rovinati apposta: devono accettare e rifiutare gli stessi, e indicare la stessa riga.
Quello che non fa
Non tiene i commenti. JSON non li ha, quindi passando da YAML a JSON spariscono, e tornando indietro non ricompaiono. Non controlla che il file sia una configurazione valida per il programma che la leggerà: che un docker-compose abbia i campi giusti lo sa solo docker. Non trasforma i tag di CloudFormation nella forma lunga che si usa nel JSON di quel servizio, li toglie e lo dice. Non indovina ogni codifica: legge UTF-8 e UTF-16, e un file salvato in un'altra si legge come Windows-1252, dichiarandolo.
Non converte altri formati. Per l'XML c'è XML in JSON e viceversa, per trasformare un elenco JSON in una tabella c'è JSON in CSV, e se il file YAML sta dentro una risposta di ChatGPT o di Claude, per tirarlo fuori pulito c'è Estrai il codice dall'AI.