如果有“!”,如何使用 PyYAML 解析 YAML在 YAML 中

     2023-03-04     176

关键词:

【中文标题】如果有“!”,如何使用 PyYAML 解析 YAML在 YAML 中【英文标题】:How to Parse YAML Using PyYAML if there are '!' within the YAML 【发布时间】:2019-02-13 20:53:53 【问题描述】:

我有一个 YAML 文件,我只想解析 description 变量;但是,我知道我的 CloudFormation 模板(YAML 文件)中的感叹号给 PyYAML 带来了麻烦。

我收到以下错误:

yaml.constructor.ConstructorError: could not determine a constructor for the tag '!Equals'

该文件有多个!Ref!Equals。如何忽略这些构造函数并获取我正在寻找的特定变量——在本例中为 description 变量。

【问题讨论】:

请提供示例数据。 Parse an AWS CloudFormation template with a YAML library的可能重复 【参考方案1】:

如果您必须处理具有多个不同标签的 YAML 文档,并且 只对其中的一部分感兴趣,你仍然应该 处理它们。如果您感兴趣的元素是嵌套的 在其他标记的构造中,您至少需要处理所有“封闭”标签 正确。

但是,您无需单独处理所有标签,您 可以编写一个可以处理映射、序列的构造函数例程 和标量注册到 PyYAML 的 SafeLoader 使用:

import yaml

inp = """\
MyEIP:
  Type: !Join [ "::", [AWS, EC2, EIP] ]
  Properties:
    InstanceId: !Ref MyEC2Instance
"""

description = []

def any_constructor(loader, tag_suffix, node):
    if isinstance(node, yaml.MappingNode):
        return loader.construct_mapping(node)
    if isinstance(node, yaml.SequenceNode):
        return loader.construct_sequence(node)
    return loader.construct_scalar(node)

yaml.add_multi_constructor('', any_constructor, Loader=yaml.SafeLoader)

data = yaml.safe_load(inp)
print(data)

给出:

'MyEIP': 'Type': ['::', ['AWS', 'EC2', 'EIP']], 'Properties': 'InstanceId': 'MyEC2Instance'

inp也可以是打开读取的文件)。

如您在上面看到的,如果您的代码中出现意外的!Join 标签,它也将继续工作, 以及任何其他标签,如!Equal。标签刚刚被删除。

由于 YAML 中没有变量,所以有点猜测是什么 您的意思是“只喜欢解析描述变量”。如果有 显式标签(例如!Description),您可以通过添加 2-3 行来过滤掉这些值 到any_constructor,通过匹配tag_suffix参数。

    if tag_suffix == u'!Description':
        description.append(loader.construct_scalar(node))

然而,映射中的某些键更有可能是标量 description, 并且您对与该键关联的值感兴趣。

    if isinstance(node, yaml.MappingNode):
        d = loader.construct_mapping(node)
        for k in d:
        if k == 'description':
            description.append(d[k])
        return d

如果您知道数据层次结构中的确切位置,您可以 当然也走data结构并提取你需要的任何东西 基于键或列表位置。特别是在那种情况下,你会更好 使用我的ruamel.yaml,这是否可以在往返模式下加载标记的 YAML 而无需 额外的努力(假设上述inp):

from ruamel.yaml import YAML

with YAML() as yaml:
    data = yaml.load(inp)

【讨论】:

我喜欢any_constructor【参考方案2】:

您可以使用自定义yaml.SafeLoader 定义自定义构造函数

import yaml

doc = '''
Conditions: 
  CreateNewSecurityGroup: !Equals [!Ref ExistingSecurityGroup, NONE]
'''

class Equals(object):
    def __init__(self, data):
        self.data = data
    def __repr__(self):
        return "Equals(%s)" % self.data

class Ref(object):
    def __init__(self, data):
        self.data = data
    def __repr__(self):
        return "Ref(%s)" % self.data

def create_equals(loader,node):
    value = loader.construct_sequence(node)
    return Equals(value)

def create_ref(loader,node):
    value = loader.construct_scalar(node)
    return Ref(value)

class Loader(yaml.SafeLoader):
    pass

yaml.add_constructor(u'!Equals', create_equals, Loader)
yaml.add_constructor(u'!Ref', create_ref, Loader)
a = yaml.load(doc, Loader)
print(a)

输出:

'Conditions': 'CreateNewSecurityGroup': Equals([Ref(ExistingSecurityGroup), 'NONE'])

【讨论】:

更好,但不需要额外的课程。特别是因为这混淆了注册这些构造函数仍然会改变所有程序未来加载的 YAML 的事实(这是 PyYAML 的缺陷)。这仍然无法处理 !Split 或任何其他可能出现的 CloudFormation 构造。 @Anthon 所有未来的 YAML 加载?我假设yaml.add_contructor 只会在我的Loader 类的范围内更改它。这是一个严重的缺陷。 我已经有一段时间没有看到它了,但是 IIRC 所有的 add_constructor 调用都添加到了 BaseConstructor 上的 class 变量 yaml_constructor。如果您处理要解析的多个不同的 YAML 文档,这确实是一个严重的问题。但是,如果您不能传入类加载器的实例,而必须传入类(或子类)本身,则这是可以预料的。这就是 ruamel.yaml 的新 API 具有 yaml = YAML() 实例化构造的主要原因:为了能够摆脱这种情况(并且在某些时候我需要打破向后兼容性)。 @Anton 当我添加一个调用yaml.load(doc) 时,我收到错误“无法确定标签'!Equals' 的构造函数”。所以,我认为它是有范围的。 (PyYAML 3.12) 它有点范围。使用答案中的代码,首先尝试将第一个add_constructor 调用的Loader 参数更改为yaml.SafeLoader。然后恢复并更改第二个add_constructor 调用的Loader 参数。 (顺便说一句,您应该开始使用 print 函数而不是 printstatement,)

pyyaml“有序”解析/生成yaml(代码片段)

...pyyaml时发现,当由字典dump成yaml文件时,顺序会被打乱,如果将字典改成OrderDict有序“字典”,则在dump的时候生成的结构会带入OrderDict的信息,所以本文提供的工具类来解决这个问题。例子如下:点击查看Github代码#-*encoding:utf-8-... 查看详情

使用 PyYAML 库解析 AWS CloudFormation 模板

】使用PyYAML库解析AWSCloudFormation模板【英文标题】:ParseanAWSCloudFormationtemplatewiththePyYAMLlibrary【发布时间】:2018-11-2714:12:40【问题描述】:我正在使用需要读取AWSCloudFormationYAML模板的PyYAML库编写自定义Python应用程序。我知道这些模... 查看详情

如何使用 PyYAML 读取 python 元组?

】如何使用PyYAML读取python元组?【英文标题】:HowtoreadapythontupleusingPyYAML?【发布时间】:2017-01-2522:52:29【问题描述】:我有一个名为input.yaml的YAML文件:cities:1:[0,0]2:[4,0]3:[0,4]4:[4,4]5:[2,2]6:[6,2]highways:-[1,2]-[1,3]-[1,5]-[2,4]-[3,4]-[5,4]start:... 查看详情

如何加载 pyYAML 文件并使用属性而不是使用字典表示法访问它?

】如何加载pyYAML文件并使用属性而不是使用字典表示法访问它?【英文标题】:HowtoloadapyYAMLfileandaccessitusingattributesinsteadofusingthedictionarynotation?【发布时间】:2012-06-1810:21:45【问题描述】:我有一个YAML配置,如下所示:config:-id:fo... 查看详情

pyyaml 加载数字为十进制

...加载数字。我找不到直接的方法来覆盖它。比较json.load,如果您想将浮点数解析为decimal.Decimals,则允许parse_float=Decimal。有什么方法可以用PyYAML完成这个吗?还是YAML规范的某些属性不建议这样做 查看详情

使用 PyYAML 在 yaml 中将文档作为原始字符串加载

...aml文档meta-info-1:val1meta-info-2:val2---Plaintext/markdowncontent!jhaha如果我使用PyYAMLload_all这个,我会得到以下信息> 查看详情

如何使用 PyYAML 创建日期时间对象

】如何使用PyYAML创建日期时间对象【英文标题】:HowtocreateadatetimeobjectwithPyYAML【发布时间】:2011-05-1104:20:06【问题描述】:我希望能够使用datetime.datetime.now()PyYAML创建一个日期时间对象。调用一些函数很容易:>>>y="""#YAML...... 查看详情

如何使用 PyYAML 重命名密钥

】如何使用PyYAML重命名密钥【英文标题】:HowdoIrenameakeywithPyYAML【发布时间】:2014-07-3000:39:54【问题描述】:我已经加载了一个我想要修改的YAML文件(模板)(键和一些值)。例如key_to_rename:a:"1"b:"2"c:"3"如何使用PyYAML查找和重命... 查看详情

为啥 PyYAML 使用生成器来构造对象?

...:53:16【问题描述】:我一直在阅读PyYAML源代码,试图了解如何定义一个合适的构造函数,我可以使用add_constructor添加该构造函数。我现在对该代码的工作原理有了很好的理解,但我仍然不明白为什么Safe 查看详情

pyyaml 的漂亮输出

...在必要时在文本编辑器中轻松编辑。不过,我的问题是,如果我将YAML引入python应用程序(我需要这样做)并编辑内容(我需要这样做),那么编写新文档通常不像我开始的那样漂亮。pyyaml文 查看详情

为啥 PyYAML 仅仅在解析 YAML 文件上花费了这么多时间?

】为啥PyYAML仅仅在解析YAML文件上花费了这么多时间?【英文标题】:WhyisPyYAMLspendingsomuchtimeinjustparsingaYAMLFile?为什么PyYAML仅仅在解析YAML文件上花费了这么多时间?【发布时间】:2013-08-2614:24:17【问题描述】:我正在解析一个大约... 查看详情

python的pyyaml模块详解(代码片段)

...原文链接简介安装简单安装从源码安装最常被问到的问题使用详解加载YAML转储YAML构造、表示和解析YAML语法文档块序列块映射流集合标量别名标签YAML标签和Python3对象字符串转换名称和模块对象简介Python的PyYAML模块是Python的YAML解... 查看详情

pyyaml 并仅对字符串使用引号

】pyyaml并仅对字符串使用引号【英文标题】:pyyamlandusingquotesforstringsonly【发布时间】:2016-11-1702:42:36【问题描述】:我有以下YAML文件:---my_vars:my_env:"dev"my_count:3当我用PyYAML读取它并再次转储它时,我得到以下输出:---my_vars:my_en... 查看详情

PyYAML 和不寻常的标签

...足够了。问题在于Unity的格式使用自定义属性,我不确定如何使用它们,因为所有示例都显示了Python和Ruby使 查看详情

解析yaml python [关闭]

...6:53:51【问题描述】:yaml标记中有一个文件a:b:xtest2testtest3如何使用python(2.7.x)和PyYAML获取x?【问题讨论】:【参考方案1】:你不能!您发布的YAML会生成一个仅包含一个键a的字典,该键映射到值"b:xtest2testtest3"-您 查看详情

pyyaml safe_load:如何忽略本地标签

】pyyamlsafe_load:如何忽略本地标签【英文标题】:pyyamlsafe_load:howtoignorelocaltags【发布时间】:2016-01-0800:12:42【问题描述】:我正在使用yaml.safe_load(),但我需要忽略标签!v2——有没有办法做到这一点但仍然使用safe_load()?【问题讨... 查看详情

使用 PyYaml 将 Python 字典转换为 yaml 文档

】使用PyYaml将Python字典转换为yaml文档【英文标题】:PythondictionariesintoyamldocumentsusingPyYaml【发布时间】:2012-12-1605:32:55【问题描述】:我有两个python字典,我想将它们写入一个yaml文件,其中包含两个文档:definitions="one":1,"two":2,"t... 查看详情

pyyaml 中的默认构造函数参数

...何执行此操作。我想表示我在YAML中定义的python类,并且如果在YAML中未指定参数,则为构造函数中的参数提供默认值。例如:>>>classTest(yaml.YAMLObject):...yaml_t 查看详情