リストまたはマップの一部を共有するためのYAML構文はありますか?


94

だから、私はこのようなことができることを知っています:

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

anotherlist: *sites

そして持っているsitelistanotherlist両方が含まれwww.foo.comていwww.bar.comます。しかし、私が本当にしたいことのためであるanotherlist含まれていwww.baz.com繰り返さなく、www.foo.comwww.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を後処理してこれを支援するためのアイデアを提示します。


注:この問題は、YAMLでのアンカーとエイリアスの標準的な使用によっても解決される場合があります。参照: YAML配列をマージする方法?
dreftymac 2017

回答:


53

マージキーのタイプはおそらくあなたが望むものです。特別な<<マッピングキーを使用してマージを示し、マッピングへのエイリアス(またはそのようなエイリアスのシーケンス)を初期化子として使用して単一のマッピングにマージできるようにします。さらに、値を明示的に上書きしたり、マージリストに存在しなかった値を追加したりすることもできます。

最初の例として、シーケンスではなくマッピングで機能することに注意することが重要です。これはあなたがそれについて考えるときに理にかなっており、あなたの例はおそらくそれが連続的である必要はないように見えます。次の(テストされていない)例のように、シーケンス値をマッピングキーに変更するだけでうまくいくはずです。

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回だけ指定できます。次に、値としてシーケンスを使用する場合、順序は重要です。この例では、関連付けられた値がないため、これは問題になりませんが、注意する必要があります。


あ、ありがとう!それはかなり役に立ちます。ただし、シーケンスに対して機能しないのは残念です。この例では、順序は重要ではありません。私が持っているものは概念的にはセットですが、それはマッピングよりもシーケンスにはるかに密接にマッピングされます。そして、私がこれから得るものの構造は重要です(それで、構造をマージするためにネストの別のレイヤーを単に追加したくなかったのはそのためです)、(すべてnull)の値を無視する必要があるマッピングがあります本当に働かない。
Ben

3
現在の公式YAML仕様yaml.org/spec/1.2/spec.htmlには何も記載されていません。そのページには、単語「マージ」、テキスト「<<」、フレーズ「キータイプ」は含まれていません。<<構文は、Python yamlパッケージでも機能します。この種の追加機能の詳細をどこで確認できるか知っていますか?
ベン

1
これは直接仕様にあるのではなく、タグリポジトリに記述されています。その他のスキーマには、一般的な説明とリンクがあります。マージキーの他に、セットと順序付きセットもあります。ただし、YAMLはセットをマッピングのタイプと見なします(たとえば、上記の例はセットとして実装できます)。あなたの言語では、結果のマッピングの値とキーを交換できますか?それを自分で実装しなければならない場合でも、私はそれがよりクリーンになると思います。少なくともすべてのデータが既にグループ化されており、YAMLは標準です。
kittemon 2012年

ただし、セットはマッピングではありません。マッピングは、キーと値の関連付けのセットです。私yaml.load(...)がPython を使用しているとき、YAMLマッピングの表現として辞書を取得します。はい、それをセットに後処理するのは簡単ですが、それが起こったことを知っている必要があります(そして、ルールが「セットがnull値を持つマップとして書き込まれる」場合、構成ファイルの読み取り/書き込み時のセマンティックの複雑さがはるかに高くなります) )。またはyaml.load(...)を使用して、結果のデータの間で後処理が必要であることを考えると、おそらく(これは既に実装済みです)に固執します。<<MERGEMERGE
ベン

2
ええ、私はその!!set作品を見つけました。ただし、あいまいな定型文は多すぎます。これらのファイルは、YAMLの専門家である必要はない人々によって、人間が読み書きできるように作成されています。人々はサイトのリストをYAMLリストとして書き留め、それからそれらをマージし、全体をセットに変換し、それをセットとして明示的にタグ付けすることを忘れないでください...私は他のいくつかの標準化されたポストを持っています- MERGEとにかく物事を一緒に処理します。あなたの助けをありがとう!
Ben

16

以前の回答が指摘したように、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で実装し、ここに公開し ました

楽しい!


2
注:この問題は、YAMLでのアンカーとエイリアスの標準的な使用によっても解決される場合があります。参照: YAML配列をマージする方法?
dreftymac 2017

11
これは、マージということだけ別のツールで動作し、このアプローチを意味していsitessites+。これはデフォルトのyaml動作ではないため、ユーザーが実装する必要があるツールを意味しますか?
stan0

7

(私が使用している解決策が将来これを検索する人に役立つ場合に備えて、自分の質問に答える)

これを行う純粋な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

あなたがリストを作成することを可能にするか、ノード内のすべてを含むマップsaltpepper他の場所で使用されています。

(マッピングの唯一のキーでfoo:あるMERGE必要があることを示すために、その外部マップを与え続けます。つまり、他のトップレベル名がない限り、それはトップレベル名として表示できません)MERGE


6

ここで2つの回答から何かを明確にするために、これはリストのYAMLでは直接サポートされていません(ただし、辞書ではサポートされています。kittemonの回答を参照してください)。


注:この問題は、YAMLでのアンカーとエイリアスの標準的な使用によっても解決される場合があります。参照: YAML配列をマージする方法?
dreftymac 2017

5

Kittemonの回答を便乗させるために、代替構文を使用してnull値のマッピングを作成できることに注意してください

foo:
    << : myanchor
    bar:
    baz:

提案された構文の代わりに

foo:
    << : myanchor
    ? bar
    ? baz

Kittemonの提案と同様に、これにより、マッピング内のアンカーへの参照を使用でき、シーケンスの問題を回避できます。Symfony Yamlコンポーネントv2.4.4では? bar構文が認識されないことがわかったので、これを行う必要があることに気付きました。


どんなmyanchor感じ?
ssc
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.