Anchors (&name) and aliases (*name) reuse a node. Merge keys (<<) copy a mapping’s entries into another, as docker-compose and many CI files do. YAML 1.2 has no merge keys, so oneyaml reads << as a plain key unless you turn them on.
use oneyaml::{Document, Settings, Value}; fn main() -> Result<(), Box<dyn std::error::Error>> { let src = "\ defaults: &defaults image: nginx:1.27 replicas: 2 web: <<: *defaults replicas: 3 worker: *defaults "; // Aliases are expanded on read; `<<` is a plain key in YAML 1.2. let v: Value = oneyaml::from_str(src)?; println!("worker.image = {:?}", v["worker"]["image"].as_str()); println!("web.image without merge keys = {:?}", v["web"]["image"].as_str()); // Turn on YAML 1.1 merge keys for docker-compose-style files. let v: Value = oneyaml::from_str_with(src, &Settings::new().merge_keys(true))?; println!("web.image = {:?}, web.replicas = {:?}", v["web"]["image"].as_str(), v["web"]["replicas"].as_u64()); // A Document keeps anchors and aliases as written, and can follow them. let doc = Document::parse(src)?; let worker = doc.get("worker").ok_or("no worker")?; println!("worker is an alias of {:?}", worker.alias_name()); let target = worker.alias_target().ok_or("no target")?; println!("target anchor {:?}, image {:?}", target.anchor(), target.get("image").and_then(|n| n.as_str())); Ok(()) }
worker.image = Some("nginx:1.27") web.image without merge keys = None web.image = Some("nginx:1.27"), web.replicas = Some(3) worker is an alias of Some("defaults") target anchor Some("defaults"), image Some("nginx:1.27")
Good to know
Settings::new().merge_keys(true)turns on merge keys alone.Compat::yaml_1_1()turns on every YAML 1.1 behavior, merge keys included.- Keys in the mapping win over merged ones:
web.replicasis 3, not 2. - Alias expansion is budgeted. Expanding aliases, merges included, counts toward the alias budget of
Limits, so a “billion laughs” file fails fast (read untrusted YAML safely). - A
Documentnever expands aliases. It keeps&and*as written, andalias_target()follows one. An edit below an alias is refused, because it would change every place that shares the node. NodeMut::push_alias,insert_aliasandinsert_mergewrite new aliases and merge keys.
Merge keys across Go, Rust and C# libraries, measured: YAML anchors, aliases and merge keys explained.