YAML错误:无法确定标记的构造函数
这与questions/44786412非常相似,但我的似乎是由YAML safe_load()触发的。我正在使用Ruamel的library和YamlReader将一堆CloudFormation碎片粘合到一个合并的模板中。爆炸符号只是不正确的YAML?YAML错误:无法确定标记的构造函数
Outputs:
Vpc:
Value: !Ref vpc
Export:
Name: !Sub "${AWS::StackName}-Vpc"
这些
Outputs:
Vpc:
Value:
Ref: vpc
Export:
Name:
Fn::Sub: "${AWS::StackName}-Vpc"
Resources:
vpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock:
Fn::FindInMap: [ CidrBlock, !Ref "AWS::Region", Vpc ]
2部分没有问题;如何让load()单独留下'Fn :: Select:'的权利。
FromPort:
Fn::Select: [ 0, Fn::FindInMap: [ Service, https, Ports ] ]
得到转换为此,现在CF不喜欢。
FromPort:
Fn::Select: [0, {Fn::FindInMap: [Service, https, Ports]}]
如果我完全展开语句,那么没有问题。我想速记只是有问题。
FromPort:
Fn::Select:
- 0
- Fn::FindInMap: [Service, ssh, Ports]
你 “砰符号” 是正确的YAML,通常这被称为标签。如果您想要使用safe_load()
以及那些必须提供!Ref
和!Sub
标记的构造函数,例如using:
ruamel.yaml.add_constructor(u'!Ref', your_ref_constructor, constructor=ruamel.yaml.SafeConstructor)
其中对于这两个标签,您应该期望处理标量值。而不是更常见的映射。
我建议您使用RoundTripLoader
而不是SafeLoader
,这将保留订单,评论等。 RoundTripLoader
是SafeLoader
的子类。
如果您正在使用ruamel.yaml> = 0.15.33,支持往返标量,你可以做(使用新的ruamel.yaml API):
import sys
from ruamel.yaml import YAML
yaml = YAML()
yaml.preserve_quotes = True
data = yaml.load("""\
Outputs:
Vpc:
Value: !Ref: vpc # first tag
Export:
Name: !Sub "${AWS::StackName}-Vpc" # second tag
""")
yaml.dump(data, sys.stdout)
获得:
Outputs:
Vpc:
Value: !Ref: vpc # first tag
Export:
Name: !Sub "${AWS::StackName}-Vpc" # second tag
在较早的0.15.X版本中,您必须自己指定标量对象的类。这很麻烦,如果你有很多对象,但允许额外的功能:
import sys
from ruamel.yaml import YAML
class Ref:
yaml_tag = u'!Ref:'
def __init__(self, value, style=None):
self.value = value
self.style = style
@classmethod
def to_yaml(cls, representer, node):
return representer.represent_scalar(cls.yaml_tag,
u'{.value}'.format(node), node.style)
@classmethod
def from_yaml(cls, constructor, node):
return cls(node.value, node.style)
def __iadd__(self, v):
self.value += str(v)
return self
class Sub:
yaml_tag = u'!Sub'
def __init__(self, value, style=None):
self.value = value
self.style = style
@classmethod
def to_yaml(cls, representer, node):
return representer.represent_scalar(cls.yaml_tag,
u'{.value}'.format(node), node.style)
@classmethod
def from_yaml(cls, constructor, node):
return cls(node.value, node.style)
yaml = YAML(typ='rt')
yaml.register_class(Ref)
yaml.register_class(Sub)
data = yaml.load("""\
Outputs:
Vpc:
Value: !Ref: vpc # first tag
Export:
Name: !Sub "${AWS::StackName}-Vpc" # second tag
""")
data['Outputs']['Vpc']['Value'] += '123'
yaml.dump(data, sys.stdout)
这给:
Outputs:
Vpc:
Value: !Ref: vpc123 # first tag
Export:
Name: !Sub "${AWS::StackName}-Vpc" # second tag
谢谢。现在我已经得到了更多,我已经删除了爆炸符号并切换到使用RoundTrip。但除了定义这些类(对定义CloudFormation的所有内部函数并不特别感兴趣),Yaml是否还有一种方法可以让单独的冒号留在任何地方,而不是解析它? –
@MatthewPatton不,解析需要完成,要知道标签的结束位置,与之相关的值是什么等等。我更新了未定义的标记对象的catch-all以支持标量(它仅支持基于映射的对象),因此您正在使用并更新相应的答案。 – Anthon
你应该回退并删除“第2部分”。在其他问题上添加标签,甚至是相关的,并非如此。你可以将它作为一个新问题提出,但现在还不清楚:您提到的七个冒号中的哪一个?也“被转换为低于”,低于什么?在冒号下面? – Anthon