Итак, я знаю, что могу сделать что-то вроде этого:
sitelist: &sites
- www.foo.com
- www.bar.com
anotherlist: *sites
И иметь, sitelist
и anotherlist
оба содержат www.foo.com
и www.bar.com
. Однако то, что я действительно хочу, - anotherlist
это также содержать www.baz.com
, без необходимости повторять www.foo.com
и www.baz.com
.
Это дает мне синтаксическую ошибку в парсере YAML:
sitelist: &sites
- www.foo.com
- www.bar.com
anotherlist: *sites
- www.baz.com
Просто используя якоря и псевдонимы, кажется невозможным делать то, что я хочу, без добавления другого уровня подструктуры, например:
sitelist: &sites
- www.foo.com
- www.bar.com
anotherlist:
- *sites
- www.baz.com
Это означает, что потребитель этого файла YAML должен знать об этом.
Есть ли способ сделать что-то подобное на чистом YAML? Или мне придется использовать некоторую пост-YAML-обработку, такую как реализация подстановки переменных или автоматического подъема определенных видов подструктуры? Я уже занимаюсь такой постобработкой, чтобы справиться с парой других вариантов использования, поэтому я не против этого. Но мои файлы YAML будут написаны людьми, а не сгенерированы машиной, поэтому я хотел бы минимизировать количество правил, которые мои пользователи должны запоминать поверх стандартного синтаксиса YAML.
Я также хотел бы проделать то же самое с картами:
namedsites: &sites
Foo: www.foo.com
Bar: www.bar.com
moresites: *sites
Baz: www.baz.com
Я просмотрел спецификацию YAML и ничего не нашел, поэтому подозреваю, что ответ - просто «нет, вы не можете этого сделать». Но если у кого-то есть идеи, это было бы здорово.
РЕДАКТИРОВАТЬ: Поскольку ответов не было, я предполагаю, что никто не заметил ничего, чего у меня нет в спецификации YAML, и что это невозможно сделать на уровне YAML. Итак, я открываю вопрос об идее пост-обработки YAML, чтобы помочь с этим, на случай, если кто-то найдет этот вопрос в будущем.
Ответы:
Тип ключа слияния , вероятно, вам нужен. Он использует специальный
<<
ключ сопоставления для указания слияний, позволяя использовать псевдоним сопоставления (или последовательность таких псевдонимов) в качестве инициализатора для слияния в одно сопоставление. Кроме того, вы по-прежнему можете явно переопределить значения или добавить другие, которых не было в списке слияния.Важно отметить, что он работает с сопоставлениями, а не с последовательностями, как ваш первый пример. Это имеет смысл, если подумать, и ваш пример, похоже, в любом случае не обязательно должен быть последовательным. Простое изменение значений вашей последовательности на сопоставление ключей должно помочь, как в следующем (непроверенном) примере:
sitelist: &sites ? www.foo.com # "www.foo.com" is the key, the value is null ? www.bar.com anotherlist: << : *sites # merge *sites into this mapping ? www.baz.com # add extra stuff
Некоторые вещи, на которые стоит обратить внимание Во-первых, поскольку
<<
это ключ, его можно указать только один раз для каждого узла. Во-вторых, при использовании последовательности в качестве значения порядок имеет значение. В приведенном здесь примере это не имеет значения, поскольку нет связанных значений, но это стоит знать.источник
yaml.load(...)
Python, я получаю словарь как представление отображения YAML. Да, это легко постобработать в набор, но я должен знать, что это произошло (и семантическая сложность при чтении / записи файлов конфигурации намного выше, если правило: «наборы записываются как карты с нулевыми значениями» ). Учитывая, что мне нужна пост-обработка междуyaml.load(...)
полученными данными и их использование, независимо от того, использую я<<
илиMERGE
, я, вероятно, буду придерживатьсяMERGE
(что я уже реализовал сейчас).!!set
работает. Однако слишком много непонятного шаблона. Эти файлы предназначены для чтения и записи людьми, которые не обязательно являются экспертами по YAML. Люди собираются записать свои списки сайтов в виде списков YAML, затем захотят объединить их и преобразовать все это в набор И не забудьте явно пометить его как набор ... У меня есть пара других стандартизированных пост- обрабатывая вещи вместе сMERGE
любым. Спасибо за вашу помощь!Как указывалось в предыдущих ответах, в YAML нет встроенной поддержки расширения списков. Предлагаю еще один способ реализовать это самостоятельно. Учти это:
defaults: &defaults sites: - www.foo.com - www.bar.com setup1: <<: *defaults sites+: - www.baz.com
Это будет преобразовано в:
defaults: sites: - www.foo.com - www.bar.com setup1: sites: - www.foo.com - www.bar.com - www.baz.com
Идея состоит в том, чтобы объединить содержимое ключа, оканчивающегося на «+», с соответствующим ключом без «+». Я реализовал это на Python и опубликовал здесь .
Наслаждайтесь!
источник
sites
иsites+
. Я имею в виду инструмент, который должен быть реализован пользователем, поскольку это неyaml
поведение по умолчанию ?(Отвечая на мой собственный вопрос, если решение, которое я использую, полезно для всех, кто будет искать это в будущем)
Поскольку для этого нет способа с использованием чистого YAML, я собираюсь реализовать это как «преобразование синтаксиса», расположенное между анализатором YAML и кодом, который фактически использует файл конфигурации. Так что моему основному приложению не нужно вообще беспокоиться о каких-либо дружественных для человека мерах по предотвращению избыточности, и оно может просто воздействовать непосредственно на результирующие структуры.
Структура, которую я собираюсь использовать, выглядит так:
foo: MERGE: - - a - b - c - - 1 - 2 - 3
Что будет преобразовано в эквивалент:
foo: - a - b - c - 1 - 2 - 3
Или с картами:
foo: MERGE: - fork: a spoon: b knife: c - cup: 1 mug: 2 glass: 3
Будет преобразовано в:
foo: fork: a spoon: b knife: c cup: 1 mug: 2 glass: 3
Более формально, после вызова анализатора YAML для получения собственных объектов из файла конфигурации, но перед передачей объектов остальной части приложения, мое приложение будет просматривать граф объектов в поисках сопоставлений, содержащих единственный ключ
MERGE
. Значение, связанное с,MERGE
должно быть либо списком списков, либо списком карт; любая другая подструктура является ошибкой.В случае списка списков вся содержащаяся карта
MERGE
будет заменена дочерними списками, объединенными вместе в порядке их появления.В случае списка карт вся содержащая карта
MERGE
будет заменена одной картой, содержащей все пары ключ / значение в дочерних картах. Если ключи перекрываются, будет использоваться значение из дочерней карты, стоящее последним вMERGE
списке.Приведенные выше примеры не так полезны, поскольку вы могли просто написать нужную структуру напрямую. Более вероятно, что это будет выглядеть так:
foo: MERGE: - *salt - *pepper
Позволяет вам создать список или карту, содержащую все в узлах
salt
иpepper
используемые в других местах.(Я продолжаю давать эту
foo:
внешнюю карту, чтобы показать, что этоMERGE
должен быть единственный ключ в ее сопоставлении, что означает, что оноMERGE
не может отображаться как имя верхнего уровня, если нет других имен верхнего уровня)источник
Чтобы прояснить что-то из двух ответов здесь, это не поддерживается непосредственно в YAML для списков (но поддерживается для словарей, см. Ответ kittemon).
источник
Чтобы воспользоваться ответом Kittemon, обратите внимание, что вы можете создавать сопоставления с нулевыми значениями, используя альтернативный синтаксис
foo: << : myanchor bar: baz:
вместо предложенного синтаксиса
foo: << : myanchor ? bar ? baz
Как и предложение Киттемона, это позволит вам использовать ссылки на якоря в отображении и избежать проблем с последовательностью. Я обнаружил, что мне нужно это сделать после того, как обнаружил, что компонент Symfony Yaml v2.4.4 не распознает
? bar
синтаксис.источник
myanchor
выглядит?