首页 > 解决方案 > ruamel.yaml:如何在顶层和其他元素内添加新元素

问题描述

ruamel.yaml文档很少,我还没有在这里找到我需要的回复。

内容my_file.yaml

desc: "blahblahblah"

Q1:我如何(以编程方式)将“size”添加为与“desc”相同级别的元素(即在树的顶层)

Q2:我如何(以编程方式)将子元素添加n 倍深

生成的文件应如下所示:

desc: 
    - "blahblahblah"
    - "desc_trans":
        - "Chinese": 
          - "Mandarin": "blahblahblah"
          - "Uyghur": "blahblahblah"
        - "Spanish": "blahblahblah"
size: "40k"

标签: pythonruamel.yaml

解决方案


ruamel.yaml文档很少,但您尝试做的主要是在 Python 级别上。您无需更改 YAML,而是从文件加载 YAML 并将其解析为数据结构,更改该数据结构(使用 Python,就像ruamel.yamlPython 包一样),然后将数据结构转储回 YAML。

首先:你不能完全得到你想要的,因为你的序列缩进是不一致的。for 的值desc缩进为 6,其中块序列指示符 ( -) 的偏移量为 4。for 的值"desc_trans"缩进为 4,偏移量为 2,for"Chinese"的最小缩进为 2。ruamel.yaml只有一对序列缩进和偏移值应用于所有(块)序列。

您正在尝试实现一些棘手的事情:

  • 加载键的标量值desc并神奇地将其转换为序列(旧的标量值是第一个元素)。代码当然应该仅在必要时进行此更改。

  • 混合了普通标量和带有多余双引号的标量。如果我没看错的话,任何不是根级映射键的标量字符串都应该用双引号引起来。您可以通过编程方式实现,但在示例中我将手动完成。

假设 Python3:

from pathlib import Path
import sys
import ruamel.yaml
from ruamel.yaml.scalarstring import DoubleQuotedScalarString as dq

yaml = ruamel.yaml.YAML()
yaml.indent(mapping=2, sequence=4, offset=2)
yaml.preserve_quotes = True
data = yaml.load(Path('my_file.yaml'))

assert isinstance(data, dict)  # check that the root-level is a dictionary like object 
data['size'] = dq('40k')

if not isinstance(data['desc'], list):
    data['desc'] = [data['desc']]  # change the non-list into a list
l = data['desc']
# make the desc_trans dict first, cannot use dict(desc_trans=[dict(Chinese=[Mandarin=....
desc_trans = []
l.append({dq('desc_trans'): desc_trans})
Chinese = {dq('Chinese'): [{dq('Mandarin'): dq('blahblahblah')}]}
Spanish = {dq('Spanish'): dq('blahblahblah')}
desc_trans.append(Chinese)
desc_trans.append(Spanish)
# the next line also could be simplified using `desc_trans.append()`
data['desc'][1]['desc_trans'][0]['Chinese'].append({dq('Uygur'): dq('blahblahblah')})

# if you want to write to a file use: out = Path('output.yaml')
out = sys.stdout
yaml.dump(data, out)

这使:

desc:
  - "blahblahblah"
  - "desc_trans":
      - "Chinese":
          - "Mandarin": "blahblahblah"
          - "Uygur": "blahblahblah"
      - "Spanish": "blahblahblah"
size: "40k"

一般来说,我建议将深层元素分配给变量,然后为其附加或分配新键。

由于ruamel.yaml实际上将映射加载到有序字典子类中,因此实际上并不需要拥有这些单键值对映射序列,您可以将这些序列作为 for"dest_trans"和 for 的值"Chinese"。省略列表可以简化代码,并且子类有一种.insert()方法可以对键顺序进行必要的控制。


推荐阅读