Schemas: how plain scalars get their type

YAML · Expert · 12 min

This is the precise answer to every 'why did this value become a boolean/number/string?' question.

YAML separates syntax from data. Parsing produces a representation graph of nodes (scalar, sequence, mapping), each with a tag. A plain scalar initially has the non-specific tag ?; quoted and block scalars have !. Tag resolution then assigns real tags according to a schema:

  • Failsafe schema: only !!map, !!seq and !!str. Every scalar is a string. Safe and predictable; some tools and config loaders can be set to it.
  • JSON schema: plain scalars must match JSON forms exactly: true, false, null, JSON numbers. Anything else is an error rather than a string.
  • Core schema (the YAML 1.2 recommendation): the JSON schema plus friendlier forms: True/TRUE, Null, ~, empty values, 0o octal, 0x hex, .inf, .nan. Everything unmatched is a string.

Only !-tagged scalars (quoted or block style) are always strings; that's the formal reason quoting works.

YAML 1.1 had no schemas in this sense, only a list of "language-independent types" with regexes that included yes/no/on/off, sexagesimals, timestamps and << merge. Most parsers' "default" behaviour is one of these schemas, possibly with extensions, which is why the same file loads differently across languages.

Many libraries let you choose: ruamel.yaml typ="safe" with version (1, 1) or (1, 2), the npm yaml package's schema: 'core' | 'json' | 'failsafe' | 'yaml-1.1', Go's yaml.v3 decoding into string fields.

Example

from ruamel.yaml import YAML

doc = "a: yes\nb: 0o17\nc: 017\nd: ~\ne: '42'\nf: 1:30\n"

y12 = YAML(typ="safe")              # YAML 1.2 core schema
print(y12.load(doc))
# {'a': 'yes', 'b': 15, 'c': 17, 'd': None, 'e': '42', 'f': '1:30'}

y11 = YAML(typ="safe")
y11.version = (1, 1)                # YAML 1.1 resolution rules
print(y11.load(doc))
# {'a': True, 'b': '0o17', 'c': 15, 'd': None, 'e': '42', 'f': 90}

# JavaScript, npm "yaml" package:
#   YAML.parse("a: yes\nb: 1", { schema: "failsafe" })  -> { a: 'yes', b: '1' }

Remember

  • Plain scalars are typed by the schema; quoted and block scalars are strings
  • Failsafe: all strings; JSON: strict JSON forms; core: JSON plus friendly forms
  • YAML 1.1 rules differ, which is why parsers disagree

Watch out for

  • Assuming two parsers agree on a file's types; check which schema each one applies.

Check yourself

  1. Under the YAML 1.2 failsafe schema, what is the type of the plain scalar 42?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: yaml.org/spec/1.2.2/#chapter-10-recommended-schemas