如何使用显式引用转储YAML? [英] How to dump YAML with explicit references?

查看:140
本文介绍了如何使用显式引用转储YAML?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

递归引用在ruamel.yamlpyyaml中可以很好地工作:

Recursive references work great in ruamel.yaml or pyyaml:

$ ruamel.yaml.dump(ruamel.yaml.load('&A [ *A ]'))
'&id001
- *id001'

但是(显然)不适用于普通参考文献:

However it (obviously) does not work on normal references:

$ ruamel.yaml.dump(ruamel.yaml.load("foo: &foo { a: 42 }\nbar: { <<: *foo }"))
bar: {a: 42}
foo: {a: 42}

我想显式创建一个引用:

I would like is to explicitly create a reference:

data = {}
data['foo'] = {'foo': {'a': 42}}
data['bar'] = { '<<': data['foo'], 'b': 43 }

$ ruamel.yaml.dump(data, magic=True)
foo: &foo
    a: 42
bar: 
    <<: *foo
    b: 43

这对于生成具有大量公共密钥的大型数据结构的YAML输出非常有用

This will be very useful to generate YAML output of large data structures that have lots of common keys

怎么可能在输出端没有争议的替换?

How is it possible without disputable re.replace on the output?

实际上ruamel.yaml.dump(data)的结果是

bar:
  '<<': &id001
    foo:
      a: 42
  b: 43
foo: *id001

所以我需要用<<替换'<<',也许用foo替换id001.

So I need to replace '<<' with << and maybe replace id001 with foo.

推荐答案

如果要创建类似的内容(至少在ruamel.yaml¹中),则应使用往返模式,该模式还保留了合并.以下不会引发断言错误:

If you want to create something like that, at least in ruamel.yaml ¹, you should use round-trip mode, which also preserves the merges. The following doesn't throw an assertion error:

import ruamel.yaml

yaml_str = """\
foo: &xyz
  a: 42
bar:
  <<: *xyz
"""

data = ruamel.yaml.round_trip_load(yaml_str)
assert ruamel.yaml.round_trip_dump(data) == yaml_str

这意味着data具有足够的信息来重新创建合并,就像在输出中一样.但是实际上,在往返模式下,合并永远不会发生.相反,检索值data['foo']['bar']['a']意味着data['foo']中没有真正的键'bar',但随后会在所附的合并映射"中查找该键.

What this means is that data has enough information to recreate the merge as it was in the output. In practise however, in round-trip mode, the merge never takes place. Instead retrieving a value data['foo']['bar']['a'] means that there is no real key 'bar' in data['foo'], but that that key is subsequently looked up in the attached "merge mappings".

对此没有公共接口(因此情况可能会发生变化),但是通过分析data并查看ruamel.yaml.comments.CommentedMap(),您会发现存在一个merge_attrib(当前为字符串_yaml_merge)以及更多内容.有用的是方法add_yaml_merge().后者采用(int,CommentedMap())元组的列表.

There is no public interface for this (so things might change), but by analyzing data and looking at ruamel.yaml.comments.CommentedMap() you can find that there is a merge_attrib (currently being the string _yaml_merge) and more useful that there is a method add_yaml_merge(). The latter takes a list of (int, CommentedMap()) tuples.

baz = ruamel.yaml.comments.CommentedMap()
baz['b'] = 196
baz.yaml_set_anchor('klm')
data.insert(1, 'baz', baz)

您需要在数据的'bar'键之前插入'baz'键,否则映射将反向.在data['bar']的合并中插入新结构后:

you need to insert the 'baz' key before the 'bar' key of data, otherwise the mapping will reverse. After insert the new structure in the merge for data['bar']:

data['bar'].add_yaml_merge([(0, baz)])
ruamel.yaml.round_trip_dump(data, sys.stdout)

给出:

foo: &xyz
  a: 42
baz: &klm
  b: 196
bar:
  <<: [*xyz, *klm]

(如果您想查看add_yaml_merge插入的内容

( if you like to see what add_yaml_merge does insert

print(getattr(data['bar'], ruamel.yaml.comments.merge_attrib))

通话前后)

如果您想完全从头开始,可以执行以下操作:

If you want to start from scratch completely you can do:

data = ruamel.yaml.comments.CommentedMap([
    ('foo', ruamel.yaml.comments.CommentedMap([('a', 42)])),
    ])
data['foo'].yaml_set_anchor('xyz')
data['bar'] = bar = ruamel.yaml.comments.CommentedMap()
bar.add_yaml_merge([(0, data['foo'])])

而不是data = ruamel.yaml.round_trip_load(yaml_str).

¹免责声明:我是该软件包的作者.

这篇关于如何使用显式引用转储YAML?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆