如何在不丢失任何非yaml关键字的情况下处理此yaml

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

我有以下 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
python yaml
1个回答
0
投票

我向生成“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
如何,它们都会保留标量。仅当您未标记时才将其注释掉 带有多余引号的标量。

映射键的顺序被保留(它不在您获得的输出中)。

如果原始映射的锚点部分有注释,这些注释将不会被自动“移动”。

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