ruby - 在不扩展标签的情况下加载 YAML?
问题描述
我正在加载 YAML 文件(特别是 CloudFormation 模板),其中可能包含!Ref
我想将其视为普通字符串的自定义标签(例如 ),即YAML.safe_load('Foo: !Bar baz')
会导致{"Foo"=>"!Bar baz"}
或类似的结果。这是因为我想在将模板转储之前遍历和操作模板。我不希望https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.htmladd_tag
下的所有内容。我目前正在使用 Psych 和 Ruby 2.0,但两者都不是严格要求。
更新 1:我的意思是说基于 Ruby 版本高于 2.0 的答案很好。
更新 2:我在这种情况下添加了 CloudFormation 标记,因为注册一堆!X
->Fn::X
转换可能是最不坏的解决方案,此时我不需要一般的 Ruby 问题。
解决方案
您不需要创建每种类型,您需要做的是创建一个通用标签处理例程,查看标签所在节点的类型(映射、序列、标量),然后创建这样一个节点作为可以附加标签的 Ruby 类型。
我不知道如何使用Psych
and来做到这一点Ruby
,但是您指出这两者都不是严格的要求,而且这种往返的大部分艰苦工作都是ruamel.yaml
for 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 不允许在映射中使用可变键。对于作为映射键的 YAM 映射,您需要使用不可变Mapping
的 fromcollections.abc
。(我不确定 Psych 是否支持这些有效的 YAML 密钥)如果您需要更新锚定/别名标量,请参阅此内容
推荐阅读
- python - SSH 到远程服务器 - 并将结果写入本地服务器
- python - 每组内累计运行百分比和每组降序排序python
- python - 如何从维基百科以实际形式提取公式到 python
- spring - Spring Boot:必须存在至少一个 JPA 元模型
- python - 正则表达式匹配html标签的开始和结束标签以及标签之间的一切(请检查图片)
- grib - 具有增量更新的 GRIB 文件
- java - 为什么两个看似相同的哈希图在被 gson 序列化时具有不同的行为?
- reactjs - 如何使用相同对象的 FetchAPI 嵌套数组
- docker - 如何使用 docker-compose 将 /var/run/docker.sock usr/bin/docker 挂载到 docker 容器?
- python - X 轴上的年份值