Jak mogę dołączyć plik YAML do innego?

Więc mam dwa pliki YAML, "A" i "B" i chcę, aby zawartość A została wstawiona do B, albo spleciona z istniejącą strukturą danych, jak tablica, albo jako potomek elementu, jak wartość dla określonego klucza hashowego.

Czy to w ogóle możliwe? Jak? Jeśli nie, jakieś wskazówki do odniesienia normatywnego?

Author: dreftymac, 2009-02-09

10 answers

Nie, YAML nie zawiera żadnych instrukcji" import "lub" include".

 241
Author: jameshfisher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-15 16:39:30

Twoje pytanie nie pyta o rozwiązanie Pythona, ale tutaj jest jedno za pomocą PyYAML .

PyYAML pozwala na dołączanie niestandardowych konstruktorów (takich jak !include) do ładowarki YAML. Dodałem katalog główny, który można ustawić tak, aby To rozwiązanie obsługiwało względne i bezwzględne odwołania do plików.

Rozwiązanie Klasy

Oto rozwiązanie oparte na klasach, które unika globalnej zmiennej głównej mojej pierwotnej odpowiedzi.

Zobacz to gist dla podobne, bardziej wytrzymałe rozwiązanie Python 3, które wykorzystuje metaclass do rejestracji niestandardowego konstruktora.

import yaml
import os.path

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)

Przykład:

foo.yaml

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

bar.yaml

- 3.6
- [1, 2, 3]

Teraz pliki można załadować używając:

>>> 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]]}
 81
Author: Josh Bode,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-08 20:31:10

Jeśli używasz Symfony w wersji YAML , jest to możliwe, tak:

imports:
    - { resource: sub-directory/file.yml }
    - { resource: sub-directory/another-file.yml }
 25
Author: daveaspinall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-14 15:12:57

Includes nie są obsługiwane bezpośrednio w yaml, o ile wiem, będziesz musiał sam dostarczyć mechanizm, jednak generalnie jest to łatwe do zrobienia.

Używałem yaml jako języka konfiguracyjnego w moich aplikacjach Pythona i w tym przypadku często definiuję konwencję w ten sposób:

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

Następnie w moim (pythonowym) kodzie robię:

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

Jedyną stroną w dół jest to, że zmienne w includes zawsze nadpisują zmienne w main i nie ma sposobu na zmianę tego pierwszeństwa przez zmiana miejsca, w którym w menu głównym pojawia się polecenie "includes:".plik yml.

W nieco innym punkcie, yaml nie obsługuje includes as its tak naprawdę nie zaprojektowany jako wyłącznie jako plik oparty na znacznikach. Co oznaczałoby include, jeśli otrzymałeś go w odpowiedzi na żądanie ajax?

 8
Author: clh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-23 18:45:22

Rozszerzając odpowiedź @ Josh_Bode, oto moje własne rozwiązanie PyYAML, które ma tę zaletę, że jest samodzielną podklasą yaml.Loader. Nie zależy to od jakichkolwiek globali na poziomie modułów, ani od modyfikacji globalnego stanu yaml modułu.

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                                                      
 7
Author: Maxy-B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-05 19:11:09

Niestety YAML nie podaje tego w swoim standardzie.

Ale jeśli używasz Ruby, istnieje klejnot zapewniający funkcjonalność, o którą prosisz, rozszerzając bibliotekę Ruby YAML: https://github.com/entwanderer/yaml_extend

 1
Author: user8419486,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-04 21:30:20

Myślę, że rozwiązanie zastosowane przez @ maxy-B wygląda świetnie. Nie udało mi się jednak z zagnieżdżonymi inkluzjami. Na przykład jeśli config_1.yaml zawiera config_2.yaml, który zawiera config_3.yaml był problem z ładowarką. Jeśli jednak po prostu skierujesz nową klasę ładowarki do siebie przy obciążeniu, to działa! W szczególności, jeśli zastąpimy starą funkcję _include bardzo nieznacznie zmodyfikowaną wersją:

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'), loader = IncludeLoader)                            
     self.root = oldRoot                                              
     return data

Po namyśle zgadzam się z innymi komentarzami, że zagnieżdżone ładowanie jest nie nadaje się do yaml w ogóle, ponieważ strumień wejściowy może nie być plikiem, ale jest bardzo przydatny!

 1
Author: PaddyM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-26 23:18:28

Z Symfony , jego obsługa yaml pośrednio pozwoli Ci zagnieżdżać pliki yaml. Sztuczka polega na wykorzystaniu opcji parameters. eg:

Pospolite.yml

parameters:
    yaml_to_repeat:
        option: "value"
        foo:
            - "bar"
            - "baz"

Config.yml

imports:
    - { resource: common.yml }
whatever:
    thing: "%yaml_to_repeat%"
    other_thing: "%yaml_to_repeat%"

Wynik będzie taki sam jak:

whatever:
    thing:
        option: "value"
        foo:
            - "bar"
            - "baz"
    other_thing:
        option: "value"
        foo:
            - "bar"
            - "baz"
 0
Author: jxmallett,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-12 04:07:59

Może to cię zainspiruje, spróbuj dostosować się do konwencji jbb:

Https://docs.openstack.org/infra/jenkins-job-builder/definition.html#inclusion-tags

- job: name: test-job-include-raw-1 builders: - shell: !include-raw: include-raw001-hello-world.sh

 0
Author: RzR,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-09 09:05:43

Prawdopodobnie nie był obsługiwany podczas zadawania pytania, ale możesz zaimportować inny plik YAML do jednego:

imports: [/your_location_to_yaml_file/Util.area.yaml]

Chociaż nie mam żadnego odniesienia online, ale to działa dla mnie.

 -6
Author: Sankalp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-08 17:27:07