Как я могу включить файл YAML в другой?

Для французского javascript js мы использовали другую кодировку:

<script src="./js/MyScript.js" type="text/javascript" charset="iso-8859-1"></script>
237
задан dreftymac 2 October 2018 в 18:29
поделиться

13 ответов

Нет, YAML не включает никаких выражений «import» или «include».

271
ответ дан jameshfisher 2 October 2018 в 18:29
поделиться

Если вы используете версию YAML Symfony , это возможно, например:

imports:
    - { resource: sub-directory/file.yml }
    - { resource: sub-directory/another-file.yml }
26
ответ дан Anders 2 October 2018 в 18:29
поделиться

Расширяя ответ @ 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                                                      
7
ответ дан Maxy-B 2 October 2018 в 18:29
поделиться

Я думаю, что решение, используемое @ maxy-B, выглядит великолепно. Однако для меня это не удалось с вложенными включениями. Например, если config_1.yaml включает config_2.yaml, который включает config_3.yaml, возникла проблема с загрузчиком. Однако, если вы просто указываете новый класс загрузчика на себя при загрузке, он работает! В частности, если мы заменим старую функцию _include очень немного измененной версией:

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

После размышлений я согласен с другими комментариями, что вложенная загрузка не подходит для yaml в целом, поскольку входной поток может не быть файлом, но это очень полезно!

1
ответ дан PaddyM 2 October 2018 в 18:29
поделиться

Включения не поддерживаются напрямую в YAML, насколько я знаю, вам придется самостоятельно создать механизм, однако, как правило, это легко сделать.

Я использовал YAML в качестве языка конфигурации в своих приложениях на Python, и в этом случае часто определяю такое соглашение:

>>> 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)))

Единственным недостатком является то, что переменные во включениях всегда будут переопределять переменные в main, и нет никакого способа изменить этот приоритет, изменив место, где в файле main.yml присутствует оператор "includes:" .

В несколько ином аспекте, YAML не поддерживает включения, поскольку они на самом деле не спроектированы так, как исключительно разметка на основе файлов. Что будет означать включение, если вы получите его в ответ на запрос AJAX? ?

11
ответ дан tk421 2 October 2018 в 18:29
поделиться

Может быть, это может вдохновить вас, попробуйте привести в соответствие с соглашениями 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
ответ дан RzR 2 October 2018 в 18:29
поделиться

С Symfony его обработка yaml косвенно позволит вам вкладывать файлы yaml. Хитрость заключается в том, чтобы использовать опцию parameters. Например:

common.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%"

Результат будет таким же как:

whatever:
    thing:
        option: "value"
        foo:
            - "bar"
            - "baz"
    other_thing:
        option: "value"
        foo:
            - "bar"
            - "baz"
-1
ответ дан jxmallett 2 October 2018 в 18:29
поделиться

Вероятно, это не было поддержано, когда был задан вопрос, но вы можете импортировать другой файл YAML в один:

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

Хотя у меня нет ссылки в Интернете, но это работает для меня.

-5
ответ дан the Tin Man 2 October 2018 в 18:29
поделиться

Ваш вопрос не требует Python-решения, но вот тот, который использует PyYAML .

PyYAML позволяет подключать пользовательские конструкторы (например, !include) к загрузчику YAML. Я включил корневой каталог, который можно настроить так, чтобы это решение поддерживало относительные и абсолютные ссылки на файлы.

Решение на основе классов

Вот решение на основе классов, которое позволяет избежать глобальной корневой переменной моего исходного ответа.

См. gist для получения аналогичного, более надежного решения 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]]}
93
ответ дан Tom 2 October 2018 в 18:29
поделиться

К сожалению, YAML не предоставляет этого в своем стандарте.

Но если вы используете Ruby, есть гем, обеспечивающий запрашиваемую вами функциональность путем расширения библиотеки ruby ​​YAML: https://github.com/entwanderer/yaml_extend

1
ответ дан user8419486 2 October 2018 в 18:29
поделиться

Для пользователей Python вы можете попробовать pyyaml-include .

Установить

pip install pyyaml-include

Использование

import yaml
from yamlinclude import YamlIncludeConstructor

YamlIncludeConstructor.add_to_loader_class(loader_class=yaml.FullLoader, base_dir='/your/conf/dir')

with open('0.yaml') as f:
    data = yaml.load(f, Loader=yaml.FullLoader)

print(data)

Предположим, у нас есть такие файлы YAML :

├── 0.yaml
└── include.d
    ├── 1.yaml
    └── 2.yaml
  • 1.yaml Содержимое]:
name: "1"
  • 2.yaml Содержимое:
name: "2"

Включение файлов по имени

  • На верхнем уровне:

    Если 0.yaml было:

!include include.d/1.yaml

Мы получим:

{"name": "1"}
  • В отображении:

    Если 0.yaml было:

file1: !include include.d/1.yaml
file2: !include include.d/2.yaml

Мы получим:

  file1:
    name: "1"
  file2:
    name: "2"
  • В последовательности:

    Если 0.yaml было:

files:
  - !include include.d/1.yaml
  - !include include.d/2.yaml

Мы получим:

files:
  - name: "1"
  - name: "2"

Примечание :

Имя файла может быть либо абсолютным (например, /usr/conf/1.5/Make.yml), либо относительным (например, ../../cfg/img.yml).

Включить файлы подстановочными знаками

Имя файла может содержать подстановочные знаки в стиле оболочки. Данные, загруженные из файла (ов), найденных с помощью подстановочных знаков, будут установлены в последовательности.

Если 0.yaml было:

files: !include include.d/*.yaml

Мы получим:

files:
  - name: "1"
  - name: "2"

Примечание :

  • Для Python>=3.5, если аргумент recursive тега !include YAML равен true, шаблон “**” будет соответствовать любым файлам и нулю или более каталогов и подкаталогов.
  • Использование шаблона “**” в больших деревьях каталогов может потребовать чрезмерного количества времени из-за рекурсивного поиска.

Чтобы включить аргумент recursive, мы напишем тег !include в режиме Mapping или Sequence:

  • Аргументы в Sequence режим:
!include [tests/data/include.d/**/*.yaml, true]
  • Аргументы в режиме Mapping:
!include {pathname: tests/data/include.d/**/*.yaml, recursive: true}
2
ответ дан xqliang 2 October 2018 в 18:29
поделиться

Стандарт YML не делает , определяют способ сделать это. И эта проблема не ограничивает себя YML. JSON имеет те же ограничения.

Много приложений, которые используют YML или JSON, базировались, конфигурации сталкиваются с этой проблемой в конечном счете. И когда это происходит, они составляют свою собственную конвенцию .

, например, для определений API чванства:

$ref: 'file.yml'

, например, для докера составляют конфигурации:

services:
  app:
    extends:
      file: docker-compose.base.yml
0
ответ дан 23 November 2019 в 02:51
поделиться

Я делаю некоторые примеры для Вашей ссылки.

import yaml

main_yaml = """
Package:
 - !include _shape_yaml    
 - !include _path_yaml
"""

_shape_yaml = """
# Define
Rectangle: &id_Rectangle
    name: Rectangle
    width: &Rectangle_width 20
    height: &Rectangle_height 10
    area: !product [*Rectangle_width, *Rectangle_height]

Circle: &id_Circle
    name: Circle
    radius: &Circle_radius 5
    area: !product [*Circle_radius, *Circle_radius, pi]

# Setting
Shape:
    property: *id_Rectangle
    color: red
"""

_path_yaml = """
# Define
Root: &BASE /path/src/

Paths: 
    a: &id_path_a !join [*BASE, a]
    b: &id_path_b !join [*BASE, b]

# Setting
Path:
    input_file: *id_path_a
"""


# define custom tag handler
def yaml_import(loader, node):
    other_yaml_file = loader.construct_scalar(node)
    return yaml.load(eval(other_yaml_file), Loader=yaml.SafeLoader)


def yaml_product(loader, node):
    import math
    list_data = loader.construct_sequence(node)
    result = 1
    pi = math.pi
    for val in list_data:
        result *= eval(val) if isinstance(val, str) else val
    return result


def yaml_join(loader, node):
    seq = loader.construct_sequence(node)
    return ''.join([str(i) for i in seq])


def main():
    # register the tag handler
    yaml.SafeLoader.add_constructor(tag='!include', constructor=yaml_import)
    yaml.SafeLoader.add_constructor(tag='!product', constructor=yaml_product)
    yaml.SafeLoader.add_constructor(tag='!join', constructor=yaml_join)

    config = yaml.load(main_yaml, Loader=yaml.SafeLoader)

    pk_shape, pk_path = config['Package']
    pk_shape, pk_path = pk_shape['Shape'], pk_path['Path']
    print(f"shape name: {pk_shape['property']['name']}")
    print(f"shape area: {pk_shape['property']['area']}")
    print(f"shape color: {pk_shape['color']}")

    print(f"input file: {pk_path['input_file']}")


if __name__ == '__main__':
    main()

производит

shape name: Rectangle
shape area: 200
shape color: red
input file: /path/src/a
0
ответ дан 23 November 2019 в 02:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: