Y a-t-il une syntaxe YAML pour partager une partie d’une liste ou une carte?

Donc, je sais que je peux faire quelque chose comme ça:

sitelist: &sites - www.foo.com - www.bar.com anotherlist: *sites 

Et as sitelist et une autre anotherlist contiennent à la fois www.foo.com et www.bar.com . Cependant, ce que je veux vraiment, c’est anotherlist autre liste contienne également www.baz.com , sans avoir à répéter www.foo.com et www.baz.com .

Cela me donne une erreur de syntaxe dans l’parsingur YAML:

 sitelist: &sites - www.foo.com - www.bar.com anotherlist: *sites - www.baz.com 

Juste en utilisant des ancres et des alias, il ne semble pas possible de faire ce que je veux sans append un autre niveau de sous-structure, tel que:

 sitelist: &sites - www.foo.com - www.bar.com anotherlist: - *sites - www.baz.com 

Ce qui signifie que le consommateur de ce fichier YAML doit en être conscient.

Y a-t-il une façon pure de YAML de faire quelque chose comme ça? Ou devrais-je utiliser un traitement post-YAML, tel que l’implémentation de la substitution de variables ou le levée automatique de certains types de sous-structures? Je fais déjà ce genre de post-traitement pour gérer quelques autres cas d’utilisation, donc je ne suis pas totalement opposé à cela. Mais mes fichiers YAML vont être écrits par des humains, pas générés par une machine, donc je voudrais minimiser le nombre de règles qui doivent être mémorisées par mes utilisateurs en plus de la syntaxe YAML standard.

J’aimerais aussi pouvoir faire la même chose avec les cartes:

 namedsites: &sites Foo: www.foo.com Bar: www.bar.com moresites: *sites Baz: www.baz.com 

J’ai fait une recherche dans la spécification YAML , et je n’ai rien trouvé, alors je suppose que la réponse est “non, vous ne pouvez pas faire ça”. Mais si quelqu’un a des idées, ce serait génial.


EDIT: Comme il n’y a pas eu de réponse, je présume que personne n’a rien trouvé dans la spécification YAML et que cela ne peut pas être fait au niveau de la couche YAML. Donc, j’ouvre la question à l’idée de post-traiter le YAML pour aider à cela, au cas où quelqu’un trouve cette question à l’avenir.

Le type de clé de fusion est probablement ce que vous voulez. Il utilise une clé de mappage spéciale pour indiquer les fusions, permettant à un alias de mappage (ou une séquence de tels alias) d’être utilisé comme initialiseur pour fusionner en un seul mappage. De plus, vous pouvez toujours remplacer explicitement les valeurs ou en append d’autres qui n’étaient pas présentes dans la liste de fusion.

Il est important de noter que cela fonctionne avec les mappages, pas les séquences comme premier exemple. Cela a du sens quand on y pense, et votre exemple ne semble pas devoir être séquentiel. Changer simplement vos valeurs de séquence en des clés de mappage devrait faire l’affaire, comme dans l’exemple suivant (non testé):

 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 

Quelques choses à remarquer Tout d'abord, puisque << est une clé, elle ne peut être spécifiée qu'une seule fois par nœud. Deuxièmement, lorsque vous utilisez une séquence comme valeur, l’ordre est significatif. Cela n'a pas d'importance dans l'exemple ici, car il n'y a pas de valeurs associées, mais cela vaut la peine de le savoir.

Comme les réponses précédentes l’ont souligné, il n’existe pas de prise en charge intégrée de l’extension des listes dans YAML. Je propose encore un autre moyen de le mettre en œuvre vous-même. Considère ceci:

 defaults: &defaults sites: - www.foo.com - www.bar.com setup1: <<: *defaults sites+: - www.baz.com 

Cela sera traité dans:

 defaults: sites: - www.foo.com - www.bar.com setup1: sites: - www.foo.com - www.bar.com - www.baz.com 

L'idée est de fusionner le contenu d'une clé se terminant par un «+» à la clé correspondante sans un «+». Je l'ai implémenté en Python et publié ici .

Prendre plaisir!

Pour clarifier quelque chose des deux réponses, ceci n’est pas supporté directement dans YAML pour les listes (mais il est supporté pour les dictionnaires, voir la réponse de kittemon).

(Répondre à ma propre question au cas où la solution que j’utilise est utile pour quiconque le recherche à l’avenir)

Sans méthode pure-YAML, je vais l’implémenter comme une “transformation de syntaxe” entre l’parsingur YAML et le code qui utilise le fichier de configuration. Donc, mon application de base ne doit pas se soucier des mesures d’évitement de la redondance, et peut agir directement sur les structures résultantes.

La structure que je vais utiliser ressemble à ceci:

 foo: MERGE: - - a - b - c - - 1 - 2 - 3 

Qui serait transformé en l’équivalent de:

 foo: - a - b - c - 1 - 2 - 3 

Ou, avec des cartes:

 foo: MERGE: - fork: a spoon: b knife: c - cup: 1 mug: 2 glass: 3 

Serait transformé en:

 foo: fork: a spoon: b knife: c cup: 1 mug: 2 glass: 3 

Plus formellement, après avoir appelé l’parsingur YAML pour obtenir des objects natifs à partir d’un fichier de configuration, mais avant de les transmettre au rest de l’application, mon application va parcourir le graphe d’objects à la recherche de mappages contenant la clé MERGE . La valeur associée à MERGE doit être soit une liste de listes, soit une liste de cartes; toute autre sous-structure est une erreur.

Dans le cas de la liste de listes, l’intégralité de la carte contenant MERGE sera remplacée par les listes enfants concaténées ensemble dans l’ordre où elles sont apparues.

Dans le cas d’une liste de cartes, la carte entière contenant MERGE sera remplacée par une seule carte contenant toutes les paires clé / valeur dans les cartes enfants. Lorsque les clés se chevauchent, la valeur de la carte enfant apparaissant en dernier dans la liste MERGE sera utilisée.

Les exemples donnés ci-dessus ne sont pas très utiles, car vous auriez pu écrire directement la structure que vous vouliez. Il est plus susceptible d’apparaître comme:

 foo: MERGE: - *salt - *pepper 

Vous permettant de créer une liste ou une carte contenant tout dans les nœuds salt et pepper étant utilisés ailleurs.

(Je continue à donner ce foo: map externe pour montrer que MERGE doit être la seule clé dans son mapping, ce qui signifie que MERGE ne peut pas apparaître comme un nom de premier niveau sauf s’il n’y a pas d’autres noms de niveau supérieur)

Pour reprendre la réponse de Kittemon, notez que vous pouvez créer des mappages avec des valeurs nulles en utilisant la syntaxe alternative

 foo: << : myanchor bar: baz: 

au lieu de la syntaxe suggérée

 foo: << : myanchor ? bar ? baz 

Comme la suggestion de Kittemon, cela vous permettra d'utiliser des références aux ancres dans le mappage et d'éviter le problème de séquence. Je me suis retrouvé à devoir le faire après avoir découvert que le composant Symfony Yaml v2.4.4 ne reprenait pas le fichier ? bar ? bar syntaxe.