简体   繁体   English

如何使用ruamel.yaml自动添加参考?

[英]How to automatically add a reference with ruamel.yaml?

I asked a very similar question some time ago, but I am still confused on how to add references on YAML dump. 不久前我问了一个非常类似的问题 ,但是我仍然对如何在YAML转储上添加引用感到困惑。

My goal is to add anchors on default values to minimize redundancy on my dump. 我的目标是在默认值上添加锚点,以最大程度地减少转储中的冗余。 So I wrote this: 所以我这样写:

import collections
import ruamel.yaml as yaml

default = {'a': 1, 'b': 2, 'c': 3}

data = {
    (1,2,3,4): {1: {'a': 10}, 2: {'b': 20}},
    (5,6,7,8): {1: {}, 2: {'a': 100, 'b': 200, 'c': 300}},
}

d = yaml.comments.CommentedMap()
d.update(default)
d.yaml_set_anchor('default')
default = d

for m, a in data.items():
    for k in a.keys():
        u = yaml.comments.CommentedMap()
        u.update(a[k])
        u.add_yaml_merge([(0, default)])
        a[k] = u

data[None] = default

def my_key_repr(self, data):
    if isinstance(data, tuple):
        return self.represent_sequence(u'tag:yaml.org,2002:seq', data, flow_style=True)
    return yaml.representer.SafeRepresenter.represent_key(self, data)

yaml.representer.RoundTripRepresenter.represent_key = my_key_repr

print yaml.dump(data, Dumper=yaml.RoundTripDumper, width=100, allow_unicode=True,
                explicit_start=True)

The expected output is: 预期的输出是:

---
~: &default
  a: 1
  c: 3
  b: 2
[1, 2, 3, 4]:
  1:
    <<: *default
    a: 10
  2:
    <<: *default
    b: 20
[5, 6, 7, 8]:
  1:
    <<: *default
  2:
    <<: *default
    a: 100
    c: 300
    b: 200

And what I get is: 我得到的是:

---
?
: &default
  a: 1
  c: 3
  b: 2
[1, 2, 3, 4]:
  1:
    <<: *default
    a: 10
  2:
    <<: *default
    b: 20
&id001 [5, 6, 7, 8]:
  1:
    <<: *id001
  2:
    <<: *id001
    a: 100
    c: 300
    b: 200

The *id001 comes from nowhere... *id001来自任何地方...

There are several problems here: 这里有几个问题:

  • If you expect the keys foo and bar to show up in your output, you'll have to specify them in your source somewhere. 如果您期望键foobar出现在输出中,则必须在源代码中的某个地方指定它们。

  • If you expect your YAML document to be implicit (ie not starting with --- ), then you should not specify explicit_start=True 如果您希望自己的YAML文档是隐式的(即,不是以---开头),则不应指定explicit_start=True

  • Keys that are None are dumped as ? 没有键被转储为? not as ~ 不如~

  • If you use update() to fill a CommentedMap() (ie a ordered dictionary) from a dict , you cannot expect the keys to be added in a specific order. 如果使用update()dict填充CommentedMap() (即有序词典),则不能期望键会以特定顺序添加。 If you want the keys in order a , c , b (as you indicate), you'll have to make sure that that is the order in which they are presented to the CommentedMap() 如果要按acb顺序(如您所指出的那样),则必须确保这是将它们呈现给CommentedMap()的顺序。

  • Since your toplevel data is not ordered, there is no guarantee that in your YAML document the toplevel mapping is the null key ( ? : or ~: ). 由于顶级data未排序,因此不能保证在YAML文档中顶级映射为null键( ? :~: :)。

The following: 下列:

from ruamel import yaml

d = {'a': 1, 'b': 2, 'c': 3}

abc = yaml.comments.CommentedMap()
abc['a'] = 100
abc['c'] = 300
abc['b'] = 200

base = [
    ('foo', {1: {'a': 10}, 2: {'b': 20}}),
    ('bar', {1: {}, 2: abc}),
]

data = yaml.comments.CommentedMap()
default = yaml.comments.CommentedMap()
for m, a in base:
    data[m] = a
for k in sorted(d):
    default[k] = d[k]
default.yaml_set_anchor('default')


for m, a in data.items():
    for k in sorted(a.keys()):
        u = yaml.comments.CommentedMap()
        u.update(a[k])
        u.add_yaml_merge([(0, default)])
        a[k] = u

data.insert(0, None, default)

x = yaml.round_trip_dump(data, width=100).replace('?\n:', '~:')
print(x)

gives exactly the output that you expected. 准确给出您期望的输出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM