我正在加载YAML文件(特别是CloudFormation模板),其中可能包含我想将其视为普通字符串的自定义标签(例如!Ref
),即YAML.safe_load('Foo: !Bar baz')
会导致{"Foo"=>"!Bar baz"}
或相似的东西。这是因为我想遍历并操纵模板,然后再将其转回。我希望不必add_tag
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html下的所有内容。我目前正在使用Psych和Ruby 2.0,但都不是严格的要求。
更新1:我的意思是说,基于Ruby版本高于2.0的答案就可以了。
更新2:我在这种情况下添加了CloudFormation标记,因为注册一大堆!X
-> Fn::X
转换可能是最糟糕的解决方案,并且我不需要通用的Ruby在这个问题上。
答案 0 :(得分:1)
好的,我们假设您在解析YAML之后得到了{"Foo"=>"!Bar baz"}
。
您用它做某事,然后又想将其转换回YAML?
{"Foo" => "!Bar baz"}.to_yaml
将产生Foo: "!Bar baz"
,这不是您开始的内容(现在是一个字符串,不评估标签)。
采用解析YAML的方法并非易事,也许应该做些其他事情。
答案 1 :(得分:0)
您不必不必创建每种类型的内容 需要做的是制作一个通用的标签处理例程, 标签所在的节点的类型(映射,序列,标量),然后 创建一个可以将标签附加到Ruby类型的节点。
我不知道如何使用Psych
和Ruby
来做到这一点,但是您表示
两者都不是严格的要求,而且大部分的辛苦工作
为ruamel.yaml
在Python
中进行这种往返
(免责声明:我是该软件包的作者)。
如果这是您的输入
文件input.yaml
:
Foo: !Bar baz
N1:
- !mytaggedmaptype
parm1: 3
parm3: 4
- !mytaggedseqtype
- 8
- 9
N2: &someanchor1
a: "some stuff"
b: 0.2e+1
f: |
within a literal scalar newlines
are preserved
N3: &someanchor2
c: 0x3
b: 4 # this value is not taken, as the first entry found is taken
['the', 'answer']: still unknown
{version: 28}: tested!
N4:
d: 5.000
<<: [*someanchor1, *someanchor2]
然后这个Python(3)程序:
import sys
from pathlib import Path
import ruamel.yaml
yaml_in = Path('input.yaml')
yaml_out = Path('output.yaml')
yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
# uncomment next line if your YAML is the outdated version 1.1 YAML but has no tag
# yaml.version = (1, 1)
data = yaml.load(yaml_in)
# do your updating here
data['Foo'].value = 'hello world!' # see the first of the notes
data['N1'][0]['parm3'] = 4444
data['N1'][0].insert(1, 'parm2', 222)
data['N1'][1][1] = 9999
data['N3'][('the', 'answer')] = 42
# and dump to file
yaml.dump(data, yaml_out)
创建output.yaml
:
Foo: !Bar hello world!
N1:
- !mytaggedmaptype
parm1: 3
parm2: 222
parm3: 4444
- !mytaggedseqtype
- 8
- 9999
N2: &someanchor1
a: "some stuff"
b: 0.2e+1
f: |
within a literal scalar newlines
are preserved
N3: &someanchor2
c: 0x3
b: 4 # this value is not taken, as the first entry found is taken
['the', 'answer']: 42
{version: 28}: tested!
N4:
d: 5.000
<<: [*someanchor1, *someanchor2]
请注意:
您可以更新标记的标量,同时将标记保留在
标量,但是由于您将这种标量替换为其分配
(而不是像列表(序列/数组)那样更新值或
字典(映射/哈希),您不能仅分配新值或
您将丢失标记信息,必须更新.value
属性。
锚点,合并,注释,引号之类的内容将被保留 特殊形式的整数(十六进制,八进制等)和浮点数。
对于映射键的YAML序列,您需要使用一个元组
(('the', 'answer')
,而不是序列(['the', 'answer']
),
因为Python不允许在映射中使用可变键。对于山药
映射是映射键,您需要使用不可变
Mapping
来自
collections.abc
。
(我不确定Psych是否支持这些有效的YAML密钥)
如果需要更新锚定/别名标量,请参见this