dump ruamel yaml - 保留原始结构

dump ruamel yaml - preserving the original structure

我有这个 yaml 文件 (file_in.yaml),

components: &base
  type1: 3  # sample comment
  type2: 0x353
  type3: 1.2.3.4
  type4: "bla"
  schemas:
    description: 'ex1' # this is comment
    description: 'ex2'

test2:
  <<: *base
  type4: 4555  # under the sea :)

yellow: &yellow
  bla: 1

collor: &yellow
  bla: 2

paint:
  color: *yellow

slot_si_value_t: &bla1
    desc: hav slot 2
    slot_number: 2 #SI_SLOT_2
    inst_max: 4

slot_si_value_t: &bla2
    desc: hav slot 4
    slot_number: 4 #SI_SLOT_4
    inst_max: 4

slot:
  - slot_si_value: *bla1
  - slot_si_value: *bla2

我用这段代码加载它,然后将它转储到另一个文件中。

import ruamel.yaml

ryaml = ruamel.yaml.YAML()
ryaml.allow_duplicate_keys = True
ryaml.preserve_quotes = True

with open("file_in.yaml") as si_file:
    si_data = ryaml.load(si_file)

with open("file_out.yaml", "w") as fp:
    ryaml.dump(si_data, fp)

file_out.yaml 看起来像这样,

components: &base
  type1: 3  # sample comment
  type2: 0x353
  type3: 1.2.3.4
  type4: "bla"
  schemas:
    description: 'ex1' # this is comment

test2:
  <<: *base
  type4: 4555  # under the sea :)

yellow:
  bla: 1

collor: &yellow
  bla: 2

paint:
  color: *yellow

slot_si_value_t: &bla1
  desc: hav slot 2
  slot_number: 2   #SI_SLOT_2
  inst_max: 4

slot:
- slot_si_value: *bla1
- slot_si_value:
    desc: hav slot 4
    slot_number: 4 #SI_SLOT_4
    inst_max: 4

我可以看到注释、引号、十六进制值和顺序都保留了下来,但是 yaml 的结构发生了变化。有没有什么方法可以指示 ruamel 转储确切的格式?

这里是并排比较,

您可以通过更改 CommentedBase.yaml_set_anchor 方法来保留所有锚点。为了 历史原因,目前仅针对锚定的标量值(即不一致)执行此操作。

然而,在 YAML 映射中有重复的键会使文档无效,因为键必须是唯一的 根据 YAML specification。为了 允许 加载 这些有问题的文档 ruamel.yaml 允许您加载此类损坏的文件 通过设置.allow_duplicate_keys来写文档,但是不支持写这样不正确的文档 并且 忽略映射中相同键 的进一步出现(在加载期间,因此您无法访问这些键的值,除非它们被锚定 在别处别名)。

这就是为什么您“丢失”键 schemas 下的 description: 'ext2' 的原因,包括以下内容 空行(这是该条目“评论”的一部分)

根映射中第二次出现 slot_si_value_t 会导致更多问题。因为 它没有被保留,&bla2 锚定映射在加载的文件中只存在一次 数据并被转储(带有锚点,因为 .yaml_set_anchor 更改),在 slot.

的值的序列
import sys
import warnings
from pathlib import Path
import ruamel.yaml


def yaml_set_anchor(self, value, always_dump=True):
    self.anchor.value = value
    self.anchor.always_dump = always_dump

ruamel.yaml.comments.CommentedBase.yaml_set_anchor = yaml_set_anchor

in_file = Path('file_in.yaml')
   
yaml = ruamel.yaml.YAML()
yaml.allow_duplicate_keys = True
yaml.preserve_quotes = True
with warnings.catch_warnings():
    warnings.simplefilter("ignore")
    data = yaml.load(in_file)
yaml.dump(data, sys.stdout)

给出:

components: &base
  type1: 3  # sample comment
  type2: 0x353
  type3: 1.2.3.4
  type4: "bla"
  schemas:
    description: 'ex1' # this is comment
test2:
  <<: *base
  type4: 4555  # under the sea :)

yellow: &yellow
  bla: 1

collor: &yellow
  bla: 2

paint:
  color: *yellow

slot_si_value_t: &bla1
  desc: hav slot 2
  slot_number: 2   #SI_SLOT_2
  inst_max: 4

slot:
- slot_si_value: *bla1
- slot_si_value: &bla2
    desc: hav slot 4
    slot_number: 4 #SI_SLOT_4
    inst_max: 4

您应该更新输入文件以处理或更改重复键。甚至 那么这将不完全是 round-trip in ruamel.yaml 因为你有不一致 缩进(例如,根级别映射为 components 和缩进两个空格 slot_si_value_t 的四个空格),并且正在规范化。