Подтвердить что ты не робот

Есть ли синтаксис YAML для совместного использования части списка или карты?

Итак, я знаю, что могу сделать что-то вроде этого:

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.

Я также хотел бы иметь возможность делать аналогичные вещи с картами:

namedsites: &sites
  Foo: www.foo.com
  Bar: www.bar.com

moresites: *sites
  Baz: www.baz.com

У меня был поиск через спецификация YAML, и я ничего не мог найти, поэтому я подозреваю, что ответ "нет" не может этого сделать ". Но если у кого-то есть какие-то идеи, это было бы здорово.


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

4b9b3361

Ответ 1

Тип ключа слияния - это, вероятно, то, что вы хотите. Он использует специальный ключ сопоставления << для указания слияний, позволяя псевдониму сопоставления (или последовательности таких псевдонимов) использоваться в качестве инициализатора для объединения в одно сопоставление. Кроме того, вы все равно можете явно переопределить значения или добавить больше, которых нет в списке слияния.

Важно отметить, что он работает с сопоставлениями, а не с последовательностями в качестве вашего первого примера. Это имеет смысл, когда вы думаете об этом, и ваш пример выглядит так, как будто, вероятно, в любом случае не обязательно быть последовательным. Простое изменение значений последовательности для сопоставления ключей должно выполнить трюк, как в следующем примере (непроверенный):

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

Некоторые вещи заметить. Во-первых, поскольку << является ключом, его можно указывать только один раз за node. Во-вторых, при использовании последовательности в качестве значения порядок значителен. Это не имеет значения в примере здесь, так как нет связанных значений, но это стоит знать.

Ответ 2

Как указывалось в предыдущих ответах, в 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 и опубликовал здесь.

Наслаждайтесь!

Ответ 3

Чтобы пояснить что-то из двух ответов здесь, это не поддерживается непосредственно в YAML для списков (но поддерживается для словарей, см. ответ kittemon).

Ответ 4

Чтобы скомпоновать ответ Kittemon, обратите внимание, что вы можете создавать сопоставления с нулевыми значениями, используя альтернативный синтаксис

foo:
    << : myanchor
    bar:
    baz:

вместо предлагаемого синтаксиса

foo:
    << : myanchor
    ? bar
    ? baz

Как и предложение Kittemon, это позволит вам использовать ссылки на привязки в рамках сопоставления и избежать проблемы с последовательностью. Я обнаружил, что мне нужно это сделать после обнаружения того, что компонент Symfony Yaml v2.4.4 не реконструирует синтаксис ? bar.

Ответ 5

(Отвечая на мой собственный вопрос, если решение, которое я использую, полезно для всех, кто ищет это в будущем)

Без метода pure-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 не может отображаться как имя верхнего уровня, если нет других имен верхнего уровня )