Загрузить YAML без расширения тегов? - PullRequest
1 голос
/ 11 мая 2019

Я загружаю 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 ]

1 голос
/ 11 мая 2019

ОК, давайте предположим, что вы получили {"Foo"=>"!Bar baz"} после анализа YAML.

Вы что-то делаете с этим, а затем хотите преобразовать его обратно в YAML?

{"Foo" => "!Bar baz"}.to_yaml приведет к Foo: "!Bar baz" - это не то, с чего вы начали (этострока теперь, теги не оцениваются).

Идти по пути синтаксического анализа YAML нетривиально, и, возможно, вместо этого нужно сделать что-то еще.

0 голосов
/ 11 мая 2019

Вам не нужно создавать каждый тип, какой вы нужно сделать, это сделать общую процедуру обработки тегов, которая смотрит на тип узла, на котором находится тег (отображение, последовательность, скаляр), затем создает такой узел как тип 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)

  • См. это , если вам нужно обновить привязанные / псевдонимные скаляры

...