だから、私は次のようなことができることを知っています:
_sitelist: &sites
- www.foo.com
- www.bar.com
anotherlist: *sites
_
sitelist
とanotherlist
の両方に_www.foo.com
_と_www.bar.com
_が含まれていること。ただし、本当に必要なのは、anotherlist
をalsoに_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 spec を検索しましたが、何も見つかりませんでしたので、答えは「これはできません」と思われます。しかし、誰かが素晴らしいアイデアを持っているなら。
EDIT:答えがなかったので、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
いくつかの注意点。まず、<<
はキーであるため、ノードごとに1回しか指定できません。第二に、値としてシーケンスを使用する場合、順序は重要です。関連する値がないため、これはここの例では重要ではありませんが、注意する価値があります。
前の回答が指摘したように、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で実装し、 here で公開しました。
楽しい!
ここの2つの回答から何かを明確にするために、これはリストのYAMLで直接サポートされていません(ただし、辞書ではサポートされています。kittemonの回答を参照してください)。
Kittemonの答えを便乗するには、代替構文を使用してnull値を使用してマッピングを作成できることに注意してください
foo:
<< : myanchor
bar:
baz:
推奨される構文の代わりに
foo:
<< : myanchor
? bar
? baz
Kittemonの提案のように、これにより、マッピング内のアンカーへの参照を使用して、シーケンスの問題を回避できます。 Symfony Yamlコンポーネントv2.4.4が? bar
構文を再認識しないことを発見した後、これを行う必要があることに気付きました。
(私が使用しているソリューションが将来これを検索する人に役立つ場合に備えて、私自身の質問に答えます)
これを行う純粋な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
がマッピング内のonlyキーでなければならないことを示すための外部マップです。つまり、MERGE
は、他のトップレベル名)