python - 用另一个文件的内容更新一个 yaml 文件
问题描述
设置:
我有两个 YAML 文件:一个带有标签和别名的大文件,另一个带有一些来自大文件的键值对的小文件。我正在使用python2.7。
问题:
我想用小值中的值更新大值中的值。
挑战:
小 yaml 可以包含大 yaml 中存在的键值对的任意组合。我还必须保留大的文字结构(不解析标签/别名)。大的很复杂,包含字典列表的字典(不要问...)。这甚至可能吗?
特别是对于这样的事情:
resources: &something
that_thing: some_stuff
some_other_stuff: this_thing
我想得到例如:
resources: &something
that_thing: some_stuff
some_other_stuff: this_thing_updated
因为这不太适合字典(我认为?)
解决方案
如果小文件的键在大文件中是唯一的,那么遍历大文件的数据结构并更新其值是相对简单的,如果键:
import sys
import ruamel.yaml
big_yaml = """\
resources: &something
that_thing: !SomeStuff
a:
- 1
- some_stuff: d
b: *something
some_other_stuff: this_thing
"""
small_yaml = """\
some_stuff: 42
some_other_stuff: 'the_other_thing'
"""
def walk_tree(d, update, done=set()):
if not update:
return
if id(d) in done:
return
if isinstance(d, dict):
done.add(id(d))
for k in d:
if k in update:
d[k] = update.pop(k)
continue # don't recurse in the newly updated value
walk_tree(d[k], update) # recurse into the values
elif isinstance(d, list):
done.add(id(d))
for elem in d:
walk_tree(elem, update)
# doing nothing for leaf-node scalars
yaml = ruamel.yaml.YAML()
# yaml.indent(mapping=2, sequence=2, offset=0)
yaml.preserve_quotes = True
big = yaml.load(big_yaml)
small = yaml.load(small_yaml)
# print(data)
walk_tree(big, small)
yaml.dump(big, sys.stdout)
这使:
resources: &something
that_thing: !SomeStuff
a:
- 1
- some_stuff: 42
b: *something
some_other_stuff: 'the_other_thing'
请注意:
- 您需要保留
id
节点的集合,以防止无限递归。这当然只有在您的大数据是递归的情况下才有必要,但它不会受到伤害。 - I
pop
的值update
,所以小文件变空并且递归提前停止。如果要更新所有匹配的键,则不要pop
,只需分配(然后您可以从中删除前两行walk_tree
) - 标记被保留,即使程序不知道如何创建一个
!Somestuff
类。这是一种魔法! - 当前仅当存在引用它的实际别名时才转储锚点。锚点被保留,因此
ruamel.yaml
可能会被修补以始终转储锚点(通常,当还添加在数据树中多次表示的新元素时,这可能会导致冲突并需要额外检查) - 保留了围绕“the_other_thing”的多余引用
- 你的映射对应。序列缩进需要保持一致,否则它们会被重新格式化。您可以取消注释该
yaml.indent
行并调整值(以匹配大文件)
或者,您可以有一个小的 YAML,如下所示:
[resources, that_thing, a, 1, some_stuff]: 42
[resources, some_other_stuff]: 'the_other_thing'
然后您可以根据键序列元素对数据结构进行确定性递归,无需检查 id 和拖动update
(只需将值作为您的第二个参数传递walk_tree
)。
如果您所有的更新都在大文件的顶层。然后不需要任何递归,因为这只是上面的一个简单的极端情况。
推荐阅读
- python - 用熊猫将行分成多行
- visual-studio-code - 使用唯一 ID 自动执行构建任务
- anaconda - 在 python 3.7 上使用 importlib 重新加载
- python - 如何在这个 pandas 数据框上正确使用 pivot ?
- node.js - 使用 node.js Promises 正确构造返回值
- javascript - 如何通过每个子文档中的两个字段过滤子文档数组
- c# - 如何使用一个 Input.GetKeyDown(KeyCode.S) 在多种材质之间切换?
- ios - 如何获取特定的主题标签帖子(更新)
- javascript - 如何在没有父节点的值/名称的情况下检索节点的数据?
- css - 使用缩放时 CSS 关键帧过渡暂停