376

したがって、「A」と「B」の 2 つの YAML ファイルがあり、A のコンテンツを B の中に挿入して、配列のように既存のデータ構造に結合するか、値のように要素の子として挿入する必要があります。特定のハッシュキーに対して。

これはまったく可能ですか?どのように?そうでない場合、規範的な参照へのポインタはありますか?

4

15 に答える 15

403

いいえ、YAML には「インポート」または「インクルード」ステートメントは含まれていません。

于 2013-03-15T16:39:30.393 に答える
140

あなたの質問は Python ソリューションを求めていませんが、ここではPyYAMLを使用しています。

PyYAML を使用すると、カスタム コンストラクター ( など!include) を YAML ローダーにアタッチできます。このソリューションが相対および絶対ファイル参照をサポートするように設定できるルート ディレクトリを含めました。

クラスベースのソリューション

これは、元の応答のグローバルルート変数を回避するクラスベースのソリューションです。

メタクラスを使用してカスタム コンストラクターを登録する、同様のより堅牢な Python 3 ソリューションについては、この要点を参照してください。

import yaml
import os

class Loader(yaml.SafeLoader):

    def __init__(self, stream):

        self._root = os.path.split(stream.name)[0]

        super(Loader, self).__init__(stream)

    def include(self, node):

        filename = os.path.join(self._root, self.construct_scalar(node))

        with open(filename, 'r') as f:
            return yaml.load(f, Loader)

Loader.add_constructor('!include', Loader.include)

例:

foo.yaml

a: 1
b:
    - 1.43
    - 543.55
c: !include bar.yaml

bar.yaml

- 3.6
- [1, 2, 3]

これで、次を使用してファイルをロードできます。

>>> with open('foo.yaml', 'r') as f:
>>>    data = yaml.load(f, Loader)
>>> data
{'a': 1, 'b': [1.43, 543.55], 'c': [3.6, [1, 2, 3]]}
于 2012-03-06T03:53:58.337 に答える
19

私の知る限り、インクルードはYAMLで直接サポートされていません。メカニズムを自分で提供する必要がありますが、これは一般的に簡単に実行できます。

Pythonアプリで構成言語としてYAMLを使用しましたが、この場合、次のような規則を定義することがよくあります。

>>> main.yml <<<
includes: [ wibble.yml, wobble.yml]

次に、私の(Python)コードで次のことを行います。

import yaml
cfg = yaml.load(open("main.yml"))
for inc in cfg.get("includes", []):
   cfg.update(yaml.load(open(inc)))

唯一の欠点は、includes内の変数が常にmain内の変数をオーバーライドすることであり、「includes:ステートメント」がmain.ymlファイルのどこにあるかを変更してその優先順位を変更する方法はありません。

少し異なる点で、YAMLは、ファイルベースのマークアップほど排他的に設計されていないため、インクルードをサポートしていません。AJAXリクエストへの応答でインクルードを取得した場合、インクルードはどういう意味ですか?

于 2012-01-23T18:45:22.610 に答える
9

@ Josh_Bode の回答を拡張して、これが私自身の PyYAML ソリューションです。これには、自己完結型のサブクラスであるという利点がありyaml.Loaderます。モジュールレベルのグローバルや、モジュールのグローバル状態の変更には依存しませんyaml

import yaml, os

class IncludeLoader(yaml.Loader):                                                 
    """                                                                           
    yaml.Loader subclass handles "!include path/to/foo.yml" directives in config  
    files.  When constructed with a file object, the root path for includes       
    defaults to the directory containing the file, otherwise to the current       
    working directory. In either case, the root path can be overridden by the     
    `root` keyword argument.                                                      

    When an included file F contain its own !include directive, the path is       
    relative to F's location.                                                     

    Example:                                                                      
        YAML file /home/frodo/one-ring.yml:                                       
            ---                                                                   
            Name: The One Ring                                                    
            Specials:                                                             
                - resize-to-wearer                                                
            Effects: 
                - !include path/to/invisibility.yml                            

        YAML file /home/frodo/path/to/invisibility.yml:                           
            ---                                                                   
            Name: invisibility                                                    
            Message: Suddenly you disappear!                                      

        Loading:                                                                  
            data = IncludeLoader(open('/home/frodo/one-ring.yml', 'r')).get_data()

        Result:                                                                   
            {'Effects': [{'Message': 'Suddenly you disappear!', 'Name':            
                'invisibility'}], 'Name': 'The One Ring', 'Specials':              
                ['resize-to-wearer']}                                             
    """                                                                           
    def __init__(self, *args, **kwargs):                                          
        super(IncludeLoader, self).__init__(*args, **kwargs)                      
        self.add_constructor('!include', self._include)                           
        if 'root' in kwargs:                                                      
            self.root = kwargs['root']                                            
        elif isinstance(self.stream, file):                                       
            self.root = os.path.dirname(self.stream.name)                         
        else:                                                                     
            self.root = os.path.curdir                                            

    def _include(self, loader, node):                                    
        oldRoot = self.root                                              
        filename = os.path.join(self.root, loader.construct_scalar(node))
        self.root = os.path.dirname(filename)                           
        data = yaml.load(open(filename, 'r'))                            
        self.root = oldRoot                                              
        return data                                                      
于 2012-09-03T17:58:44.373 に答える