使用pyyaml生成带有替换的yaml锚/引用

问题描述 投票:1回答:2

您可以使用人工编写的YAML执行的操作是:

foo: &foo_anchor
  key1: v1
  key2: v2
  key3: v3
bar:
  <<: *foo_anchor
  key2: override_value

我想像使用PyYAML一样以编程方式生成输出。似乎很棘手!据我所知,默认情况下,PyYAML仅在遇到相等的对象时才生成锚/引用(并且顺序可能未定义,而在此示例中,bar必须引用foo,而不必相反) )。我已经尝试了一些方法-定义YamlReference类并在重写的Dumper.serialize_node方法中检查其标记-但尝试执行以下操作:

        if node.tag.endswith('magic.prefix.YamlReference'):
            alias = node.value[0].value
            self.emit(yaml.events.AliasEvent(alias))
            super(Dumper, self).anchor_node(node.value[1])
            super(Dumper, self).serialize_node(node.value[1], parent, idx)

满足预期的事件流。这可能吗?

python yaml pyyaml
2个回答
1
投票
好,你可以做这样的事情:

import yaml class Merger(object): pass def merger_representer(dumper, data): return dumper.represent_scalar(u'tag:yaml.org,2002:merge', '<<') yaml.add_representer(Merger, merger_representer) foo = {'key1': 'v1', 'key2': 'v2', 'key3': 'v3'} root = { 'foo': foo, 'bar': { Merger(): foo, 'key2': 'override_value' } } print(yaml.dump(root, sort_keys=False))

输出为:

foo: &id001 key1: v1 key2: v2 key3: v3 bar: <<: *id001 key2: override_value

sort_keys=False确保键的正确顺序,它需要Python> = 3.7和PyYAML> = 5.1(感谢@tinita)。您无法控制所生成的锚名称,但是此YAML等效于您的名称。

[您需要Merger类来强制PyYAML发出<<(使用普通的字符串键,它将发出'<<',以免与合并键混淆)。


-1
投票
实现此目标的一种方法是制作一个包含适当内容的类有关合并信息的信息,并且仍然允许查找data['bar']['key1']。当然,您需要使用适当的表示符正确转储此类。

这是ruamel.yaml(免责声明,我是该软件包的作者)确实允许来回合并地图:

import sys import ruamel.yaml yaml_str = """\ foo: &foo_anchor key1: v1 key2: v2 key3: v3 bar: <<: *foo_anchor key2: override_value """ yaml = ruamel.yaml.YAML() data = yaml.load(yaml_str) yaml.dump(data, sys.stdout)

给出:

foo: &foo_anchor key1: v1 key2: v2 key3: v3 bar: <<: *foo_anchor key2: override_value

所以我建议您看一下CommentedMap类,这是怎么回事在constructor.pyrepresenter.py中处理。 

如果可以升级到ruamel.yaml,则可以执行以下操作:

cm = ruamel.yaml.comments.CommentedMap data = cm() data['foo'] = foo = cm(key1='v1', key2='v2', key3='v3') foo.yaml_set_anchor('foo_anchor') data['bar'] = bar = cm(key2='override_value') bar.add_yaml_merge([(0, foo)]) yaml = ruamel.yaml.YAML() yaml.dump(data, sys.stdout)

从头开始,它提供了与您期望的类似的东西:

foo: &foo_anchor key1: v1 key2: v2 key3: v3 bar: <<: *foo_anchor key2: override_value

当然,以下工作按预期进行:

print(list(data['bar'].keys())) print(data['bar']['key3'])

给出:

['key2', 'key1', 'key3'] v3

© www.soinside.com 2019 - 2024. All rights reserved.