所以我有两个其文件的"A"和"B"和我想的内容待插入的内部B,或是接到现有的数据结构,像一个数组,或者作为一个孩子中的一个元素,如价值的一定的散列关键。

这可能吗?怎么样?如果不是,任何指向一个规范性参考?

有帮助吗?

解决方案

没有,YAML不包括任何形式的“进口”或“包括”语句。

其他提示

您的问题不要求一个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]]}

如果您正在使用的Symfony的版本YAML 的,这是可能的,就像这样:

imports:
    - { resource: sub-directory/file.yml }
    - { resource: sub-directory/another-file.yml }

包括不直接支持在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.yml文件

在一个稍微不同的角度,YAML不支持包括作为其没有真正设计为专门为基于文件标记起来。什么将一个包含的意思是如果你在一个AJAX请求的响应了吗?

扩大对@ 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                                                      

为蟒蛇用户,你可以试试 pyyaml-包括.

安装

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)

考虑我们必须这样 文件:

├── 0.yaml
└── include.d
    ├── 1.yaml
    └── 2.yaml
  • 1.yaml 's的内容:
name: "1"
  • 2.yaml 's的内容:
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).

包括文件通过符

文件名称可以包含壳式通配符。数据加载的文件(s)通过找到符,将设置在一个序列。

如果 0.yaml 为:

files: !include include.d/*.yaml

我们会得到:

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

注意到:

  • 对于 Python>=3.5, ,如果 recursive 参数 !include 标记 true, ,该模式 “**” 将符合任何文件和零或多个目录和子目录。
  • 使用 “**” 图案的大目录中的树木的可能消耗大量的时间,因为递归的搜索。

为了使 recursive 论点,我们会写信的 !include 标记 MappingSequence 方式:

  • 参数 Sequence 方式:
!include [tests/data/include.d/**/*.yaml, true]
  • 参数 Mapping 方式:
!include {pathname: tests/data/include.d/**/*.yaml, recursive: true}

不幸的是YAML不在其标准提供这一点。

但如果你使用Ruby,有提供你通过扩展红宝石YAML库要求的功能的宝石: https://github.com/entwanderer/yaml_extend

我认为@所使用的溶液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作为输入流可能不是一个文件,但它是非常有用!

也许这能鼓舞你,尽量对准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

标准YAML 1.2本身不包括该功能。然而许多实现提供了一些扩展这样做。

我介绍了Java和snakeyaml:1.24实现它的一种方式(Java库来解析/发射YAML文件),它允许创建一个自定义YAML标签实现以下目标(你会看到我用它来加载定义的测试套件在几个YAML文件和我把它作为列表工作的包括用于目标test:节点):

# ... yaml prev stuff

tests: !include
  - '1.hello-test-suite.yaml'
  - '3.foo-test-suite.yaml'
  - '2.bar-test-suite.yaml'

# ... more yaml document

下面是一个级的Java,允许处理所述!include标签。文件从类路径(Maven的资源目录)加载:

/**
 * Custom YAML loader. It adds support to the custom !include tag which allows splitting a YAML file across several
 * files for a better organization of YAML tests.
 */
@Slf4j   // <-- This is a Lombok annotation to auto-generate logger
public class MyYamlLoader {

    private static final Constructor CUSTOM_CONSTRUCTOR = new MyYamlConstructor();

    private MyYamlLoader() {
    }

    /**
     * Parse the only YAML document in a stream and produce the Java Map. It provides support for the custom !include
     * YAML tag to split YAML contents across several files.
     */
    public static Map<String, Object> load(InputStream inputStream) {
        return new Yaml(CUSTOM_CONSTRUCTOR)
                .load(inputStream);
    }


    /**
     * Custom SnakeYAML constructor that registers custom tags.
     */
    private static class MyYamlConstructor extends Constructor {

        private static final String TAG_INCLUDE = "!include";

        MyYamlConstructor() {
            // Register custom tags
            yamlConstructors.put(new Tag(TAG_INCLUDE), new IncludeConstruct());
        }

        /**
         * The actual include tag construct.
         */
        private static class IncludeConstruct implements Construct {

            @Override
            public Object construct(Node node) {
                List<Node> inclusions = castToSequenceNode(node);
                return parseInclusions(inclusions);
            }

            @Override
            public void construct2ndStep(Node node, Object object) {
                // do nothing
            }

            private List<Node> castToSequenceNode(Node node) {
                try {
                    return ((SequenceNode) node).getValue();

                } catch (ClassCastException e) {
                    throw new IllegalArgumentException(String.format("The !import value must be a sequence node, but " +
                            "'%s' found.", node));
                }
            }

            private Object parseInclusions(List<Node> inclusions) {

                List<InputStream> inputStreams = inputStreams(inclusions);

                try (final SequenceInputStream sequencedInputStream =
                             new SequenceInputStream(Collections.enumeration(inputStreams))) {

                    return new Yaml(CUSTOM_CONSTRUCTOR)
                            .load(sequencedInputStream);

                } catch (IOException e) {
                    log.error("Error closing the stream.", e);
                    return null;
                }
            }

            private List<InputStream> inputStreams(List<Node> scalarNodes) {
                return scalarNodes.stream()
                        .map(this::inputStream)
                        .collect(toList());
            }

            private InputStream inputStream(Node scalarNode) {
                String filePath = castToScalarNode(scalarNode).getValue();
                final InputStream is = getClass().getClassLoader().getResourceAsStream(filePath);
                Assert.notNull(is, String.format("Resource file %s not found.", filePath));
                return is;
            }

            private ScalarNode castToScalarNode(Node scalarNode) {
                try {
                    return ((ScalarNode) scalarNode);

                } catch (ClassCastException e) {
                    throw new IllegalArgumentException(String.format("The value must be a scalar node, but '%s' found" +
                            ".", scalarNode));
                }
            }
        }

    }

}

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"

也许有人不支持,当有人问,但你可以导入其他YAML文件分割成一个:

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

虽然我没有任何的在线参考,但这个对我的作品。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top