shijie lu shijie lu - 1 month ago 7
YAML Question

How can the YAML following references override the front one?

merge:
- &LEFT { x: 1, y: 1, r: 1 }
- &BIG { x: 2, y: 2, r: 2 }
- &SMALL { x: 3, y: 3, r: 3}

- # Override
<< : [ *BIG, *LEFT, *SMALL ]
x: 1
label: big/left/small


I get the output:

{
merge:
[
{ x: 1, y: 1, r: 1 },
{ x: 2, y: 2, r: 2 },
{ x: 3, y: 3, r: 3 },
{ x: 1, y: 2, r: 2, label: 'big/left/small' }
]
}


But the results do not meet my expectation, the last one in the merge object I hope it be

{ x: 1, y: 3, r: 3, label: 'big/left/small' }.


How can I do with the YAML syntax ?

Answer

You cannot do this with YAML syntax, and your expectations are unfounded on multiple levels.

  1. An anchored element (whether a sequence element or not) doesn't magically disappear when it is used in merge alias or any other alias nor on the basis of it being an anchor
  2. A toplevel mapping key (merge) doesn't magically disappear because its value is a sequence scalar that contains an element with a merge indicator

The Merge Key Language-Independent Type documentation doesn't indicate such a deletion and neither does the YAML specification. The anchors (and aliases) are not normally preserved in the representation in the language you use for loading your YAML, as per the YAML specs. Therefore it is normally not possible to find the anchored elements and delete them after loading.

A generic solution would be to have top another toplevel key default key that "defines" the anchors and work only with the value associated with the merge key:

import ruamel.yaml

yaml_str = """\
default:
  - &LEFT { x: 1, y: 1, r: 1 }
  - &BIG { x: 2, y: 2, r: 2 }
  - &SMALL { x: 3, y: 3, r: 3}

merge:
  # Override
  << : [ *BIG, *LEFT, *SMALL ]
  x: 1
  label: big/left/small
"""

data = ruamel.yaml.load(yaml_str)['merge']
print(data)

gives:

{'x': 1, 'r': 2, 'y': 2, 'label': 'big/left/small'}

(the order of the keys in your output is of course random)

Comments