我有以下 yaml 片段 我想解析指向锚点的指针,而且我不想丢失将由另一个程序处理的
!flatten
和 !ref
。
输入:
_ip_context: &ip_context
ip_restriction: !flatten
- !ref 'constant::public_cidr_blocks'
policies:
- file: policies/somepolicy.json
context:
<<: *ip_context
所需输出:
policies:
- file: policies/somepolicy.json
context:
ip_restriction: !flatten
- !ref 'constant::public_cidr_blocks'
我尝试了ChatGpt 制作的这个程序。但它并没有得到我想要的:
import sys
import yaml
yaml_content = """
_ip_context: &ip_context
ip_restriction: !flatten
- !ref 'constant::public_cidr_blocks'
policies:
- file: policies/somepolicy.json
context:
<<: *ip_context
"""
class FlattenConstructor(yaml.constructor.SafeConstructor):
def construct_flatten(self, node):
return self.construct_sequence(node)
class RefConstructor(yaml.constructor.SafeConstructor):
def construct_ref(self, node):
return self.construct_scalar(node)
yaml.add_constructor('!flatten', FlattenConstructor.construct_flatten, Loader=yaml.SafeLoader)
yaml.add_constructor('!ref', RefConstructor.construct_ref, Loader=yaml.SafeLoader)
data = yaml.load(yaml_content, Loader=yaml.SafeLoader)
class FlattenRepresenter(yaml.representer.SafeRepresenter):
def represent_flatten(self, data):
return self.represent_sequence('!flatten', data)
class RefRepresenter(yaml.representer.SafeRepresenter):
def represent_ref(self, data):
return self.represent_scalar('!ref', data)
yaml.add_representer(list, FlattenRepresenter.represent_flatten)
yaml.add_representer(str, RefRepresenter.represent_ref)
#with open('output.yaml', 'w') as outfile:
yaml.dump(data, sys.stdout, default_flow_style=False,Dumper=yaml.SafeDumper)
这是输出:
_ip_context:
ip_restriction: &id001
- constant::public_cidr_blocks
policies:
- context:
ip_restriction: *id001
file: policies/somepolicy.json
我向生成“AI”程序询问了一些有关 python 和 YAML 的问题(关于这些问题,我 想象一下我知道一两件事),并对它给出的答案大笑起来。
代码不会为标记和非标记序列和标量创建不同的类型。所以 如果表示代码可以工作,输出将在所有输出上附加标签。 该代码也无法执行任何操作来阻止创建锚点和别名。
删除别名
without removing the anchor
描述于here。
在你的情况下,事情一方面更简单,因为你只需删除加载的数据结构中你不想要的部分,
摆脱锚点/和别名。
ruamel.yaml
将为您保留标签,无需任何特殊操作,但它也会保留合并键,
不是你想要的。要摆脱它,您可以更新代表者,但这需要复制一个相当大的
方法 represent_mapping
中的一段代码。所以我的偏好是递归地遍历数据结构并
摆脱合并信息(这同样取决于 ruamel.yaml
内部结构,因此固定您使用的版本):
import sys
import pathlib
import ruamel.yaml
file_name = Path('input.yaml')
def un_merge(d):
if isinstance(d, dict):
if d.merge:
for kvs in d.merge:
for k1, v1 in kvs[1].items(): # kvs[0] is the position of the merge
d[k1] = v1
delattr(d, ruamel.yaml.comments.merge_attrib)
for k, v in d.items():
un_merge(k)
un_merge(v)
elif isinstance(d, list):
for elem in d:
un_merge(elem)
yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
data = yaml.load(file_name)
del data['_ip_context']
un_merge(data)
yaml.dump(data, sys.stdout)
给出:
policies:
- file: policies/somepolicy.json
context:
ip_restriction: !flatten
- !ref 'constant::public_cidr_blocks'
这看起来就是你想要的输出。
默认情况下
ruamel.yaml
删除多余的引号,以及 constant::public_cidr_blocks
周围的引号
解析器不需要正确处理标量中的冒号(并非全部如此)。然而在标记内
无论preserve_quotes
如何,它们都会保留标量。仅当您未标记时才将其注释掉
带有多余引号的标量。
映射键的顺序被保留(它不在您获得的输出中)。
如果原始映射的锚点部分有注释,这些注释将不会被自动“移动”。