02: Struttura: documenti, mapping, indentazione
← 01 - YAML e la frattura tra 1.1 e 1.2 · Indice · successivo → 03 - Scalari, quoting e blocchi multiriga
2.1 I tre mattoni
YAML ha esattamente tre cose: scalari (valori singoli), sequenze (liste) e mapping (dizionari chiave-valore). Tutto il resto è combinazione di questi.
# mapping
nome: Ale
attivo: true
# sequenza
linguaggi:
- python
- lua
# mapping annidati e sequenze di mapping
server:
host: 192.168.1.10
porte:
- 80
- 443
utenti:
- nome: admin
ruolo: owner
- nome: ospite
ruolo: readerL’ultimo pezzo merita attenzione: una sequenza di mapping si scrive con il - seguito
dalla prima chiave, e le chiavi successive allineate a quella (non al trattino). È la
struttura più comune in assoluto nei file reali, ed è quella dove si sbaglia di più.
2.2 Indentazione: le regole esatte
Dalla specifica, testualmente:
- L’indentazione è definita come zero o più caratteri spazio a inizio riga.
- Per garantire la portabilità, i tab non devono essere usati nell’indentazione.
- Ogni nodo deve essere indentato più del suo genitore.
- Tutti i nodi fratelli devono usare esattamente lo stesso livello di indentazione.
Tre conseguenze pratiche:
1. I tab sono vietati nell’indentazione, punto. Non “sconsigliati”: la grammatica
ammette solo spazi. Configura l’editor perché il tasto Tab inserisca spazi nei file .yaml.
2. Non esiste un numero “giusto” di spazi, purché sia coerente fra fratelli. La convenzione universale è 2. Usala.
3. I trattini delle sequenze “contano” come indentazione percepita. Questo è legale:
porte:
- 80
- 443e anche questo:
porte:
- 80
- 443Entrambi validi. La seconda forma è più leggibile e la impongono molti linter
(indent-sequences: true è il default di yamllint).
2.3 Dove i tab sono invece ammessi
Dettaglio che sorprende: i tab non sono vietati ovunque. La specifica li ammette come separatore fra token (dopo i due punti, per esempio) e dentro il contenuto degli scalari.
Ma PyYAML è più severo della specifica e li rifiuta anche lì. ✅ verificato:
x: [a,\tb] produce ScannerError. js-yaml invece lo accetta.
Morale: non è una zona da esplorare. Niente tab nei file YAML.
2.4 Flow style: la sintassi compatta
Accanto allo stile a blocchi esiste quello “flow”, identico a JSON:
porte: [80, 443, 8080]
utente: {nome: admin, ruolo: owner}Quando usarlo: liste corte di valori semplici. Quando non usarlo: strutture annidate, perché diventa illeggibile e perde il vantaggio dei diff riga per riga.
Attenzione a una regola: in stile a blocchi il valore non può essere attaccato ai due
punti. a:1 è la stringa "a:1", non un mapping. Serve lo spazio: a: 1.
✅ verificato: è la causa dell’errore mapping values are not allowed here che vedrai
mille volte (07 - Strumenti, sicurezza, debug e reference).
2.5 Documenti
Un file YAML può contenere più documenti, separati da ---:
---
nome: primo
---
nome: secondo
...
---
nome: terzo---significa in realtà “fine delle direttive, inizio del documento”....chiude esplicitamente un documento (raro, ma legale).- Un file con un solo documento non ha bisogno di nulla: il
---iniziale è opzionale (yamllint per default lo chiede, ma è solo stile).
Dove serve davvero: Kubernetes, dove è normale mettere più risorse in un file.
In Python si leggono con yaml.safe_load_all(), non safe_load().
E c’è l’uso che conosci già: nel frontmatter Markdown, --- delimita il blocco YAML
in cima al file. Non è esattamente lo stesso meccanismo, ma la sintassi è quella.
2.6 Commenti
# commento su riga intera
porta: 8080 # commento in codaDue regole precise:
- Il
#deve essere preceduto da uno spazio per essere un commento.a: foo#barè la stringafoo#bar;a: foo #barèfoopiù un commento. ✅ verificato entrambi. - I commenti non sopravvivono a un round-trip. La specifica dice che sono un
dettaglio di presentazione: se un programma legge il tuo file e lo riscrive, i commenti
spariscono. Le eccezioni sono le librerie “round-trip” (
ruamel.yaml,yamldi npm) e basta.
Questo ha un’implicazione concreta: se un’interfaccia grafica può riscrivere il tuo file, non metterci commenti importanti. Vale per l’editor delle automazioni di Home Assistant e per l’editor delle properties di Obsidian.
Il caso
color: #FF0000✅ verificato: produce
{'color': None}. Il#preceduto da spazio apre un commento e il valore resta vuoto. Va scrittocolor: '#FF0000'. Nessun errore, nessun avviso: il valore semplicemente non c’è.
2.7 Chiavi
Normalmente sono stringhe semplici. Tre cose da sapere:
Chiavi duplicate. La specifica dice che sono un errore. I parser non sono d’accordo.
✅ verificato su k: 1 seguito da k: 2:
| Parser | Risultato |
|---|---|
| PyYAML | {'k': 2}, silenzioso, vince l’ultima |
| js-yaml | eccezione duplicated mapping key |
yaml (npm) | errore |
PyYAML è l’anomalia ed è il parser più diffuso. In un file di 400 righe, una chiave
duplicata è invisibile in code review e non dà errore. È il singolo errore di
configurazione più insidioso che esista in YAML. Il rimedio è il linter: yamllint ha la
regola key-duplicates attiva di default.
Chiavi non stringa. YAML permette numeri, booleani e perfino liste come chiavi. Il linguaggio che legge, spesso no. ✅ verificato in Python:
1: uno
true: booleano→ {1: 'booleano'}. La chiave 1 è sparita: in Python True == 1, quindi la seconda
sovrascrive la prima. Nessun avviso. Se hai chiavi numeriche, virgolettale.
Chiavi esplicite ?. Servono quando la chiave è multiriga o è essa stessa una
struttura. Le incontrerai raramente; sapere che esistono basta.
2.8 Uno stile che non ti crea problemi
# 1. due spazi, mai tab
# 2. sequenze indentate sotto la chiave
# 3. valori ambigui virgolettati con apici singoli
# 4. una riga vuota fra i blocchi logici
# 5. niente commenti in file che una UI può riscrivere
servizio:
nome: api
versione: '1.10'
porte:
- 8080
- 8443
ambiente:
LOG_LEVEL: debug
REGION: 'NO'Esercizi
- Scrivi una sequenza di mapping (tre server con nome, ip e lista di porte) senza guardare gli esempi. Poi validala.
- Metti di proposito un tab nell’indentazione e leggi l’errore: impara a riconoscerlo.
- Duplica una chiave in un file e verifica che
python3 -c "import yaml;print(yaml.safe_load(open('f.yaml')))"non protesti. Poi passaciyamllintsopra. - Scrivi un file multi-documento e leggilo con
safe_load_all.