加载YAML而不扩展标签?

时间:2019-05-10 22:40:17

标签: ruby yaml amazon-cloudformation

我正在加载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在这个问题上。

2 个答案:

答案 0 :(得分:1)

好的,我们假设您在解析YAML之后得到了{"Foo"=>"!Bar baz"}

您用它做某事,然后又想将其转换回YAML?

{"Foo" => "!Bar baz"}.to_yaml将产生Foo: "!Bar baz",这不是您开始的内容(现在是一个字符串,不评估标签)。

采用解析YAML的方法并非易事,也许应该做些其他事情。

答案 1 :(得分:0)

您不必不必创建每种类型的内容 需要做的是制作一个通用的标签处理例程, 标签所在的节点的类型(映射,序列,标量),然后 创建一个可以将标签附加到Ruby类型的节点。

我不知道如何使用PsychRuby来做到这一点,但是您表示 两者都不是严格的要求,而且大部分的辛苦工作 为ruamel.yamlPython中进行这种往返 (免责声明:我是该软件包的作者)。

如果这是您的输入 文件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