Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/grails/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如果存在';,如何使用PyYAML解析YAML';在YAML内_Python_Constructor_Yaml_Amazon Cloudformation_Pyyaml - Fatal编程技术网

Python 如果存在';,如何使用PyYAML解析YAML';在YAML内

Python 如果存在';,如何使用PyYAML解析YAML';在YAML内,python,constructor,yaml,amazon-cloudformation,pyyaml,Python,Constructor,Yaml,Amazon Cloudformation,Pyyaml,我有一个YAML文件,我只想解析description变量;然而,我知道我的CloudFormation模板(YAML文件)中的感叹号给PyYAML带来了麻烦 我收到以下错误: yaml.constructor.ConstructorError:无法确定标记“”的构造函数!等于“ 该文件有许多!参考和!等于。如何忽略这些构造函数并获取我正在寻找的特定变量——在本例中,是说明变量。您可以使用自定义yaml.SafeLoader定义自定义构造函数 import yaml doc = ''' Con

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

我收到以下错误:

yaml.constructor.ConstructorError:无法确定标记“”的构造函数!等于“


该文件有许多
!参考
!等于
。如何忽略这些构造函数并获取我正在寻找的特定变量——在本例中,是
说明
变量。

您可以使用自定义
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的
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
也可以是打开阅读的文件)

如您所见,如果出现意外的
,也将继续工作!“加入”
标记显示在您的代码中, 以及任何其他标记,如
!相等
。标签刚刚掉下来

因为YAML中没有变量,所以有点猜测是什么 您的意思是“只想解析描述变量”。如果有 显式标记(例如
!Description
),您可以通过添加2-3行来过滤掉值 通过匹配
tag\u后缀
参数,添加到
any\u构造函数

    if tag_suffix == u'!Description':
        description.append(loader.construct_scalar(node))
然而,更可能的是,在标量描述的映射中存在某个键, 并且您对与该键关联的值感兴趣

    if isinstance(node, yaml.MappingNode):
        d = loader.construct_mapping(node)
        for k in d:
        if k == 'description':
            description.append(d[k])
        return d
如果您知道数据层次结构中的确切位置,您可以 本课程还将遍历
数据
结构并提取您需要的任何内容
基于关键点或列表位置。尤其是在这种情况下,你最好
使用my
ruamel.yaml
,是否可以在往返模式下加载标记的yaml,而无需 额外工作量(假设上述
inp
):


请提供示例数据。可能是Better的副本,但不需要额外制作一个类。特别是因为这混淆了这样一个事实,即注册这些构造函数仍然会改变程序将来加载的所有YAML(这是PyYAML的缺陷)。这仍然无法处理
!Split
或任何其他可能出现的CloudFormation构造。@在所有将来的YAML加载中?我假设
yaml.add_constructor
只会在我的
Loader
类的范围内更改它。这是一个严重的缺陷。我已经有一段时间没有看到它了,但是IIRC所有的add_构造函数调用都添加到类变量
yaml_构造函数
上的
BaseConstructor
。如果要解析多个不同的YAML文档,那么这确实是一个严重的问题。但是,如果您不能传入类装入器的实例,而必须传入类(或子类)本身,则应该这样做。这就是为什么
ruamel.yaml
的新API具有
yaml=yaml()
实例化构造的主要原因:为了能够摆脱这种情况(在某个时候,我需要因此中断向后兼容性)。@Anton当我添加一个调用
yaml.load(doc)
时,我得到了错误“无法确定标记“”的构造函数!等于'。因此,我认为它的作用域是有限的。(PyYAML 3.12)它的作用域是有限的。如果您的代码与您的答案相同,请首先尝试将第一个
add\u构造函数的
Loader
调用的
Loader
参数更改为
yaml.SafeLoader
。然后revent并更改第二个
add\u构造函数的
参数。(顺便说一句,你应该开始使用
print
函数而不是
print
语句,)我喜欢
任何构造函数。
from ruamel.yaml import YAML

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