Как ссылаться на псевдоним карты в YAML - PullRequest
0 голосов
/ 20 января 2019

У меня такое ощущение, что это невозможно, но у меня есть фрагмент YAML, который выглядит следующим образом:

.map_values: &my_map
  a: 'D'
  b: 'E'
  a: 'F'

section:
  stage: *my_map['b']

Я бы хотел, чтобы stage имел значение E.

Возможно ли это в YAML? Я пробовал почти все воплощения замещения, которые я могу придумать.

1 Ответ

0 голосов
/ 20 января 2019

Поскольку в вашем отображении есть дубликат ключа, который не допускается в YAML 1.2 (и должен хотя бы выдавать предупреждение в YAML 1.1) это не собираюсь работать, но даже если вы исправите это, вы не сможете этого сделать только с якорями и псевдонимами.

Единственной заменой, подобной замене, которая доступна в YAML, является «Независимый от языка слияния тип ключа» . На него косвенно ссылаются в спецификации YAML, и он не включен в него, но доступен в большинстве анализаторов.

Единственное, что позволяет это сделать, - это "обновить" отображение парами значений ключа одного или нескольких других отображений, , если ключ еще не существует в отображении. Для этого вы используете специальный ключ <<, который принимает псевдоним или список псевдонимов.

Не существует средства, указанного в спецификации YAML , для разыменования частичных ключей.

В некоторых системах используются шаблоны, генерирующие YAML, но здесь есть две основные проблемы:

  • сами языки шаблонов часто конфликтуют с индикаторами в синтаксисе YAML, делает шаблон недействительным YAML

  • , даже если шаблон может быть загружен как действительный YAML, а извлеченные значения необходимы для обновить другие части шаблона, вам нужно будет проанализировать ввод дважды (один раз, чтобы получить значения для обновления шаблона, а затем для анализа обновленного шаблона). Учитывая потенциал сложность YAML и относительная медленная скорость его синтаксических анализаторов, это может быть непомерно большим

Что вы можете сделать, это создать какой-нибудь тег (например, !lookup) и заставить его конструктор интерпретировать этот узел. Поскольку узел снова должен быть действительным YAML, вам нужно решить, использовать ли последовательность или отображение. Вы должны будете включить некоторый специальный синтаксис для значений в обоих случаях, а также для ключа (например, <<, используемый в слияниях) в случае отображений.

В примерах я исключил ложные одинарные кавычки, в зависимости от ваши реальные ценности, они вам, конечно, могут понадобиться.

Пример использования последовательности:

.map_values: &my_map
  a: D
  b: E
  c: F

section: !Lookup
- *my_map
- stage: <b>

Пример использования сопоставления:

.map_values: &my_map
  a: D
  b: E
  c: F

section: !Lookup
  >>: *my_map
  stage: <b>

Оба могут быть сделаны для построения данных на лету (т. Е. Без прошлого необходима обработка загрузки вашей структуры данных). Например. используя Python и последовательность "стиль" в input.yaml:

import sys
import ruamel.yaml
from pathlib import Path

input = Path('input.yaml')

yaml = ruamel.yaml.YAML(typ='safe')
yaml.default_flow_style = False

@yaml.register_class
class Lookup:
    @classmethod
    def from_yaml(cls, constructor, node):
         """
            this expects a two entry sequence, in which the first is a mapping X, typically using
            an alias
            the second entry should be an mapping, for which the values which have the form <key>
            are looked up in X
            non-existing keys will throw an error during loading.
         """
         X, res = constructor.construct_sequence(node, deep=True)
         yield res
         for key, value in res.items():
             try:
                 if value.startswith('<') and value.endswith('>'):
                   res[key] = X[value[1:-1]]
             except AttributeError:
                 pass
         return res


data = yaml.load(input)
yaml.dump(data, sys.stdout)

что дает:

.map_values:
  a: D
  b: E
  c: F
section:
  stage: E

Следует отметить несколько вещей:

  • использование <...> является произвольным, вам не нужны ни начало, ни маркер конца Я рекомендую использовать некоторые символы, которые не имеют особое значение в YAML, поэтому вам не нужно указывать свои значения. Вы можете, например, использовать некоторые хорошо распознаваемая точка Unicode, но они, как правило, труднее набирать в редакторе.
  • когда вызывается from_yaml, якорь еще не полностью построен. Так что X это пустой диктат это заполняется позже. Конструкция с yield реализует двухэтапный процесс: сначала мы верните res "как есть" обратно конструктору, а затем обновите его. Этап конструктора загрузчик знает, как обрабатывать это автоматически, когда он получает генератор вместо «нормального» значения.
  • try .. except предназначен для обработки значений сопоставления, которые не являются строками (то есть числа, даты, логические значения).
  • вы также можете делать замены в ключах, просто убедитесь, что вы удалили старый ключ

Поскольку теги являются стандартными YAML, вышеприведенное должно быть так или иначе выполнено в любом Парсер YAML, независимый от языка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...