如何将YAML文件包含在另一个文件中?

如何将YAML文件包含在另一个文件中?,yaml,transclusion,Yaml,Transclusion,所以我有两个YAML文件,“A”和“B”,我希望A的内容被插入到B中,或者拼接到现有的数据结构中,比如数组,或者作为元素的子元素,比如某个散列键的值 这可能吗?怎么用?如果没有,YAML中不直接支持任何指向规范性引用的指针?Includes。据我所知,您必须自己提供一种机制,但这通常很容易做到 我在python应用程序中使用了YAML作为配置语言,在这种情况下,我经常定义如下约定: >>> main.yml <<< includes: [ wibble.yml

所以我有两个YAML文件,“A”和“B”,我希望A的内容被插入到B中,或者拼接到现有的数据结构中,比如数组,或者作为元素的子元素,比如某个散列键的值


这可能吗?怎么用?如果没有,YAML中不直接支持任何指向规范性引用的指针?

Includes。据我所知,您必须自己提供一种机制,但这通常很容易做到

我在python应用程序中使用了YAML作为配置语言,在这种情况下,我经常定义如下约定:

>>> main.yml <<<
includes: [ wibble.yml, wobble.yml]
唯一的缺点是includes中的变量总是覆盖main中的变量,并且无法通过更改main.yml文件中“includes:语句”出现的位置来更改优先级


另一点稍有不同,YAML不支持include,因为它并不是专门设计为基于文件的标记。如果您在对AJAX请求的响应中得到它,那么include意味着什么?

您的问题并不要求Python解决方案,但这里有一个使用

PyYAML允许您将自定义构造函数(例如
!include
)附加到YAML加载程序。我已经包含了一个根目录,可以对其进行设置,以便此解决方案支持相对和绝对文件引用

基于类的解决方案 这是一个基于类的解决方案,它避免了原始响应的全局根变量

类似的、更健壮的Python3解决方案使用元类来注册自定义构造函数,请参见本文

导入yaml
导入操作系统
类加载器(yaml.SafeLoader):
定义初始化(自,流):
self.\u root=os.path.split(stream.name)[0]
超级(加载器,自身)。\uuuu初始化\uuuuuu(流)
def包括(自身、节点):
filename=os.path.join(self.\u根,self.construct\u标量(节点))
将open(filename,'r')作为f:
返回yaml.load(f,装载机)
Loader.add_构造函数(“!include”,Loader.include)
例如:

foo.yaml

a: 1
b:
    - 1.43
    - 543.55
c: !include bar.yaml
- 3.6
- [1, 2, 3]
bar.yaml

a: 1
b:
    - 1.43
    - 543.55
c: !include bar.yaml
- 3.6
- [1, 2, 3]
现在可以使用以下方法加载文件:

以open('foo.yaml','r')作为f: >>>数据=yaml.load(f,装载机) >>>资料 {'a':1,'b':[1.43543.55],'c':[3.6[1,2,3]}
根据@Josh_Bode的答案进行扩展,下面是我自己的PyYAML解决方案,它的优点是作为
yaml.Loader
的一个自包含子类。它不依赖于任何模块级全局变量,也不依赖于修改
yaml
模块的全局状态

导入yaml、os
类IncludeLoader(yaml.Loader):
"""                                                                           
yaml.Loader子类在配置中处理“!include path/to/foo.yml”指令
文件夹。使用文件对象构造时,包含的根路径
默认为包含文件的目录,否则为当前目录
工作目录。在这两种情况下,根路径都可以被
`root`关键字参数。
当包含的文件F包含自己的文件时!include指令,路径为
相对于F的位置。
例子:
YAML文件/home/frodo/one-ring.yml:
---                                                                   
名称:一环
特价:
-根据佩戴者调整尺寸
影响:
- !包含路径/to/invisibility.yml
YAML文件/home/frodo/path/to/invisibility.yml:
---                                                                   
名称:隐形
信息:你突然消失了!
加载:
data=IncludeLoader(打开('/home/frodo/one-ring.yml','r')).get_data()
结果:
{'Effects':[{'Message':'突然你消失了!','Name':
'隐形'}],'名字':'一环','特价品':
['resize-to-wearer']}
"""                                                                           
定义初始化(self,*args,**kwargs):
超级(包括阅读器、自身)。\uuuuu初始值(*args,**kwargs)
self.add_构造函数(“!include”,self._include)
如果kwargs中的“根”:
self.root=kwargs['root']
elif isinstance(self.stream,文件):
self.root=os.path.dirname(self.stream.name)
其他:
self.root=os.path.curdir
定义包括(自身、加载程序、节点):
oldRoot=self.root
filename=os.path.join(self.root、loader.construct\u标量(节点))
self.root=os.path.dirname(文件名)
data=yaml.load(打开(文件名'r'))
parameters:
    yaml_to_repeat:
        option: "value"
        foo:
            - "bar"
            - "baz"
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"
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
├── 0.yaml
└── include.d
    ├── 1.yaml
    └── 2.yaml
name: "1"
name: "2"
!include include.d/1.yaml
{"name": "1"}
file1: !include include.d/1.yaml
file2: !include include.d/2.yaml
  file1:
    name: "1"
  file2:
    name: "2"
files:
  - !include include.d/1.yaml
  - !include include.d/2.yaml
files:
  - name: "1"
  - name: "2"
files: !include include.d/*.yaml
files:
  - name: "1"
  - name: "2"
!include [tests/data/include.d/**/*.yaml, true]
!include {pathname: tests/data/include.d/**/*.yaml, recursive: true}
# ... yaml prev stuff

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

# ... more yaml document
$ref: 'file.yml'
services:
  app:
    extends:
      file: docker-compose.base.yml
shape name: Rectangle
shape area: 200
shape color: red
input file: /path/src/a
# xxx.yaml
CREATE_FONT_PICTURE:
  PROJECTS:
    SUNG: &id_SUNG
      name: SUNG
      work_dir: SUNG
      output_dir: temp
      font_pixel: 24


  DEFINE: &id_define !ref [*id_SUNG]  # you can use config['CREATE_FONT_PICTURE']['DEFINE'][name, work_dir, ... font_pixel]
  AUTO_INIT:
    basename_suffix: !dict_ref [*id_define, name, !product [5, 3, 2]]  # SUNG30

# ↓ This is not correct.
# basename_suffix: !dict_ref [*id_define, name, !product [5, 3, 2]]  # It will build by Deep-level. id_define is Deep-level: 2. So you must put it after 2. otherwise, it can't refer to the correct value.
foo: !? $import('B.yaml')
bar: Hello
$ yglu A.yaml
foo:
  bar: Hello
  dep: !- b
  foo: !? $import($_.dep.toUpper() + '.yaml')