Warum aus „no“ false wird: Wahrheitswerte in YAML 1.1 und 1.2

Das „Norway Problem“ ist die bekannteste Falle bei YAML-Wahrheitswerten: Der Ländercode NO für Norwegen wird von einem YAML-1.1-Parser nicht als Text gelesen, sondern als false. Der Grund ist, dass YAML 1.1 viele Wörter als Boolean erkennt, nicht nur true und false. Die Lösung ist einfach: Setze Texte, die wie ein Boolean, eine Zahl oder ein anderer Spezialwert aussehen, in Anführungszeichen.

Wie ein YAML-1.2-Parser deine Datei liest, siehst du im YAML-zu-JSON-Konverter: Dort bleibt NO ein Text, 3.10 wird aber zur Zahl 3.1. Ein YAML-1.1-Parser wie PyYAML liest dieselbe Datei anders, wie die Beispiele unten zeigen.

Das Problem im Beispiel

laender:
  - DE
  - FR
  - NO
  - SE

Mit einem YAML-1.1-Parser wie PyYAML ergibt das:

import yaml

print(yaml.safe_load(open("laender.yaml")))
# {'laender': ['DE', 'FR', False, 'SE']}

Aus Norwegen wurde False. Das gibt keinen Fehler, die Daten sind einfach stillschweigend falsch. Besonders ärgerlich ist das bei Listen von Ländercodes, Sprachcodes oder Konfigurationsschaltern.

Welche Wörter YAML 1.1 als Boolean liest

Die Typ-Beschreibung von YAML 1.1 nennt für Wahrheitswerte diese Schreibweisen:

Wert Schreibweisen
wahr y, Y, yes, Yes, YES, true, True, TRUE, on, On, ON
falsch n, N, no, No, NO, false, False, FALSE, off, Off, OFF

Gemischte Schreibweisen wie nO zählen nicht. Auch die Einzelbuchstaben y und n stehen nur in der Spezifikation: PyYAML zum Beispiel erkennt sie in der Praxis nicht, sondern nur yes/no, true/false und on/off in den drei Varianten. Ob ein Parser die Einzelbuchstaben umsetzt, hängt also von der Bibliothek ab.

Typische Opfer neben NO:

sprache: no        # Norwegisch → false
schalter: on       # → true
antwort: Yes       # → true

Weitere Überraschungen in YAML 1.1

Booleans sind nicht die einzige Falle. YAML 1.1 deutet auch diese Werte um:

rechte: 0755       # Oktalzahl → 493
dauer: 1:20        # Sexagesimalzahl (Basis 60) → 80
version: 3.10      # Fließkommazahl → 3.1
  • 0755: Eine führende Null bedeutet in YAML 1.1 „oktal“. Aus 0755 wird die Dezimalzahl 493. Das trifft vor allem Dateirechte, aber auch Postleitzahlen wie 01067.
  • 1:20: YAML 1.1 kennt Zahlen zur Basis 60, gedacht für Zeitangaben und Winkel. PyYAML liest 1:20 deshalb als Ganzzahl 80. Uhrzeiten wie 12:30 sind betroffen.
  • 3.10: Das ist ein Problem, das auch YAML 1.2 hat. 3.10 ist eine Fließkommazahl, und die hat den Wert 3.1. Die Null am Ende geht verloren. Versionsnummern wie 3.10 (Python) oder 1.20 brauchen deshalb immer Anführungszeichen. Eine Version mit zwei Punkten wie 1.2.3 ist dagegen keine Zahl und bleibt ein Text.

Was YAML 1.2 anders macht

YAML 1.2 (2009) hat das Boolean-Chaos aufgeräumt. Im Core Schema gelten nur noch true, True, TRUE und false, False, FALSE als Wahrheitswerte. yes, no, on, off, y und n sind ganz normale Texte, NO bleibt also "NO".

Auch bei Zahlen ist 1.2 strenger: Oktalzahlen schreibst du als 0o755, und 0755 ist eine gewöhnliche Dezimalzahl mit dem Wert 755. Sexagesimalzahlen gibt es nicht mehr, 1:20 bleibt ein Text.

Welche Parser welche Version nutzen

Das Verhalten hängt von der Bibliothek ab, nicht von deiner Datei:

  • PyYAML (Python) folgt YAML 1.1. Hier tritt das Norway Problem auf.
  • yaml von Eemeli Aro (JavaScript, npm-Paket yaml) nutzt standardmäßig YAML 1.2. Über die Option version: "1.1" kannst du das 1.1-Verhalten einschalten.
  • js-yaml ab Version 4 folgt dem 1.2 Core Schema, yes und no bleiben dort Texte.

Bei anderen Bibliotheken schaust du am besten in die Dokumentation oder testest NO direkt. Für Dateien, die von mehreren Werkzeugen gelesen werden, ist das ein Grund mehr, die Werte zu quoten: Dann ist das Ergebnis in jedem Parser gleich, egal welche Version er spricht.

Die Lösung: Texte in Anführungszeichen setzen

Ein Wert in Anführungszeichen ist immer ein Text. Beide Formen funktionieren:

laender:
  - "DE"
  - "NO"
rechte: "0755"
version: "3.10"
dauer: "1:20"

Einfache Anführungszeichen ('NO') tun dasselbe wie doppelte. Mit doppelten kannst du zusätzlich Escape-Sequenzen wie \n verwenden. Quoten musst du nur, wenn der Wert sonst als etwas anderes gelesen würde, aber bei Ländercodes, Versionen und Codes mit führenden Nullen schadet es nie.

Wenn du ein Boolean wirklich willst, schreibe true oder false: Diese beiden Schreibweisen funktionieren in YAML 1.1 und 1.2 gleich.

Beim Umwandeln von JSON nach YAML

Das Problem tritt auch in die andere Richtung auf: Steht in JSON der Text "NO", darf das erzeugte YAML nicht einfach NO enthalten, sonst liest ein 1.1-Parser daraus false. Der JSON-zu-YAML-Konverter auf formatierer.de setzt solche Werte deshalb in Anführungszeichen, sodass sie Texte bleiben. Die Umwandlung läuft komplett lokal im Browser, deine Daten werden an keinen Server gesendet.

{ "land": "NO", "version": "3.10", "an": true }
land: "NO"
version: "3.10"
an: true

Der echte Boolean true bleibt dabei unverändert, der Text "NO" wird gequotet.

Kurz gesagt

  • YAML 1.1 liest yes, no, on, off (und je nach Parser y, n) in verschiedenen Schreibweisen als Boolean. Daher wird NO zu false.
  • YAML 1.1 deutet außerdem 0755 als Oktalzahl und 1:20 als Zahl zur Basis 60. 3.10 wird in 1.1 und 1.2 zur Zahl 3.1.
  • YAML 1.2 kennt im Core Schema nur true und false; PyYAML folgt noch 1.1, yaml (Eemeli Aro) und js-yaml 4 folgen 1.2.
  • Setze mehrdeutige Texte in Anführungszeichen, dann sind sie in jedem Parser Texte.

Weiterlesen: Was ist YAML?, JSON vs. YAML, YAML-Fehler finden und beheben. Zum Ausprobieren: YAML zu JSON und JSON zu YAML.