Используйте заполнители в yaml
Есть ли способ использовать заполнители в yaml следующим образом:
foo: &FOO
<<propname>>:
type: number
default: <<default>>
bar:
- *FOO
propname: "some_prop"
default: "some default"
4 ответа
контекст
- YAML версия 1.2
- пользователь хочет включить переменные заполнители в YAML
проблема
- YAML изначально не поддерживает переменные заполнители
- Якоря и псевдонимы допускают некоторый уровень абстракции и косвенности, но они не работают как переменные заполнители, которые могут быть вставлены в произвольные области по всему тексту YAML. Они должны быть размещены как отдельные узлы YAML
- Есть некоторые дополнительные библиотеки, которые поддерживают произвольные переменные-заполнители, но они не являются частью собственной спецификации YAML
пример
Рассмотрим следующий пример YAML. Это правильно сформированный синтаксис YAML, однако он использует (нестандартные) фигурные скобки со встроенными выражениями.
Встроенные выражения не дают желаемого результата в YAML, потому что они не являются частью собственной спецификации YAML, но они помогают проиллюстрировать, что доступно со стандартным YAML, а что нет.
part01_customer_info:
cust_fname: "Homer"
cust_lname: "Himpson"
cust_motto: "I love donuts!"
cust_email: homer@himpson.org
part01_government_info:
govt_sales_taxrate: 1.15
part01_purchase_info:
prch_unit_label: "Bacon-Wrapped Fancy Glazed Donut"
prch_unit_price: 3.00
prch_unit_quant: 7
prch_product_cost: "{{prch_unit_price * prch_unit_quant}}"
prch_total_cost: "{{prch_product_cost * govt_sales_taxrate}}"
part02_shipping_info:
cust_fname: "{{cust_fname}}"
cust_lname: "{{cust_lname}}"
ship_city: Houston
ship_state: Hexas
part03_email_info:
cust_email: "{{cust_email}}"
mail_subject: Thanks for your DoughNutz order!
mail_notes: |
We want the mail_greeting to have all the expected values
with filled-in placeholders (and not curly-braces).
mail_greeting: |
Greetings {{cust_fname}} {{cust_lname}}!
We love your motto "{{cust_motto}}" and we agree with you!
Your total purchase price is {{prch_total_cost}}
Thank you for your order!
объяснение
- Замены, помеченные ЗЕЛЕНЫМ, легко доступны в стандартном YAML с использованием якорей, псевдонимов и ключей слияния.
- Заметки, помеченные ЖЕЛТЫМ, технически доступны в стандартном YAML, но не без специального объявления типа или какого-либо другого механизма связывания.
- Заметки, помеченные в RED, недоступны в стандартном YAML и требуют использования какого-либо механизма форматирования строк или шаблонов строк (например, Python
str.format
, например).
подробности
Часто запрашиваемая функция для YAML - это возможность вставлять произвольные переменные заполнители, которые поддерживают произвольные перекрестные ссылки и выражения, которые относятся к другому контенту в том же (или включенном) файле (ах) YAML.
YAML поддерживает привязки и псевдонимы, но эта функция не поддерживает произвольное размещение заполнителей и выражений где-либо в тексте YAML. Они работают только с узлами YAML.
Библиотеки дополнений YAML
Существуют библиотеки расширений YAML, но они не являются частью собственной спецификации YAML.
- анзибль
- https://docs.ansible.com/ansible-container/container_yml/template.html
- (поддерживает множество расширений YAML, однако это инструмент Orchestration, который излишним, если вы просто хотите YAML)
- https://github.com/kblomqvist/yasha
- https://github.com/dreftymac/dynamic.yaml
- https://bitbucket.org/djarvis/yamlp
обходные
- Используйте YAML в сочетании с системой шаблонов, такой как Jinja2 или Twig
- Используйте библиотеку расширений YAML
- использование
sprintf
или жеstr.format
функциональность стиля от языка хостинга
Смотрите также
- Строковая интерполяция в YAML
- Как ссылаться на "настройки" YAML из другого места в том же файле YAML?
- Используйте YAML с переменными
- Как я могу включить файл YAML в другой?
- Передача переменных в рельсовый файл интернационализации рельсов
- Может ли один объект YAML ссылаться на другой?
- Есть ли способ ссылаться на константу в yaml с рельсами?
- https://learnxinyminutes.com/docs/yaml/
С помощью Yglu Structural Templating ваш пример можно записать:
foo: !()
!? $.propname:
type: number
default: !? $.default
bar:
!apply .foo:
propname: "some_prop"
default: "some default"
Отказ от ответственности: я автор или Yglu.
Я полагаю, что https://get-ytt.io/ будет приемлемым решением вашей проблемы
Я также хотел использовать шаблоны в файлах, и я нашел действительно полезным в качестве отправной точки. После нескольких часов исследований и кодирования это мой ответ, пожалуйста, дайте мне знать, если/как я могу это улучшить.
Я не делаю ничего особенного, я пытаюсь использовать синтаксис шаблонов строк Python и немного злоупотребляю методом форматирования строк. Так что это все шаблоны строк Python и подстановка, которые творят здесь магию. Я изменил способ ответ dreftymac, которым ответ dreftymac создал его шаблон
yaml
файл для использования в качестве примера.
YAML:
part01_customer_info:
cust_fname: "Homer"
cust_lname: "Himpson"
cust_motto: "I love donuts!"
cust_email: homer@himpson.org
part01_government_info:
govt_sales_taxrate: 1.15
part01_purchase_info:
prch_unit_label: "Bacon-Wrapped Fancy Glazed Donut"
prch_unit_price: 3.00
prch_unit_quant: 7
prch_product_cost: "eval!#{part01_purchase_info[prch_unit_price]} * {part01_purchase_info[prch_unit_quant]}"
prch_total_cost: "eval!#{part01_purchase_info[prch_product_cost]} * {part01_government_info[govt_sales_taxrate]}"
part02_shipping_info:
cust_fname: "{part01_customer_info[cust_fname]}"
cust_lname: "{part01_customer_info[cust_lname]}"
ship_city: Houston
ship_state: Hexas
part03_email_info:
cust_email: "{part01_customer_info[cust_email]}"
mail_subject: Thanks for your DoughNutz order!
mail_notes: |
We want the mail_greeting to have all the expected values
with filled-in placeholders (and not curly-braces).
mail_greeting: |
Greetings {part01_customer_info[cust_fname]} {part01_customer_info[cust_lname]}!
We love your motto "{part01_customer_info[cust_motto]}" and we agree with you!
Your total purchase price is {part01_purchase_info[prch_total_cost]}
я изменился
{{}}
к{}
и добавилeval!#
который является идентификатором
Питон:
from pprint import pprint
import yaml
EVAL_IDENTIFIER = "eval!#"
def eval_math_expr(val):
if val.startswith(EVAL_IDENTIFIER):
val = val.replace(EVAL_IDENTIFIER, "")
val = eval(val)
return val
def str_template_substitute(full, val=None, initial=True):
val = val or full if initial else val
if isinstance(val, dict):
for k, v in val.items():
val[k] = str_template_substitute(full, v, False)
elif isinstance(val, list):
for idx, i in enumerate(val):
val[idx] = str_template_substitute(full, i, False)
elif isinstance(val, str):
# NOTE:
# Templating shouldn't be confused or tasked with extra work.
# I am attaching evaluation to string substitution here,
# just to prove this can be done.
val = eval_math_expr(val.format(**full))
return val
data = yaml.load(open('./data.yml'))
str_template_substitute(data)
pprint(data)
Примечание. Эта функция довольно мощная, поскольку она может работать со словарями, в которые конвертируются JSON/YAML и многие другие форматы в python.