python - 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"
解决方案
ruamel.yaml
文档很少,但您尝试做的主要是在 Python 级别上。您无需更改 YAML,而是从文件加载 YAML 并将其解析为数据结构,更改该数据结构(使用 Python,就像ruamel.yaml
Python 包一样),然后将数据结构转储回 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()
方法可以对键顺序进行必要的控制。