如何将 YAML 文件包含在另一个文件中?
所以我有两个 YAML 文件,“A”和“B”,我希望将 A 的内容插入到 B 中,要么拼接到现有的数据结构中,如数组,要么作为元素的子元素,如值对于某个哈希键。
这有可能吗? 如何? 如果没有,是否有任何指向规范参考的指针?
So I have two YAML files, "A" and "B" and I want the contents of A to be inserted inside B, either spliced into the existing data structure, like an array, or as a child of an element, like the value for a certain hash key.
Is this possible at all? How? If not, any pointers to a normative reference?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(17)
也许这可以启发您,尝试与 jbb 约定保持一致:
https://docs.openstack.org/infra/jenkins-job-builder/definition.html#inclusion-tags
- 工作:
名称:测试作业-include-raw-1
建设者:
- 壳:
!include-raw: include-raw001-hello-world.sh
Maybe this could inspire you, try to align to jbb conventions:
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
结合其他答案,这里有一个简短的解决方案,无需重载
Loader
类,它可以与任何对文件操作的加载程序一起使用:# noinspection PyTypeChecker
是为了防止 PEP 检查警告 将node: yaml.Node
传递给loader.construct_scalar()
时,预期类型为“ScalarNode”,但得到了“Node”。如果 yaml.load 输入流不是文件流,则此解决方案将失败,因为在这种情况下 loader.name 不包含路径:
在我的用例中,我知道只有YAML 文件将被包含在内,因此解决方案可以进一步简化:
甚至可以使用 lambda 进行单行:
Combining other answers, here is a short solution without overloading
Loader
class and it works with any loader operating on files:# noinspection PyTypeChecker
is there to prevent PEP-check warning Expected type 'ScalarNode', got 'Node' instead when passingnode: yaml.Node
toloader.construct_scalar()
.This solution fails if
yaml.load
input stream is not file stream, asloader.name
does not contain the path in that case:In my use case, I know that only YAML files will be included, so the solution can be simplified further:
or even one-liner using lambda:
添加上面 @Joshbode 的初始答案,我稍微修改了代码片段以支持 UNIX 风格的通配符模式。
不过我还没有在 Windows 中测试过。 我面临着将大型 yaml 中的数组拆分为多个文件以方便维护的问题,并且正在寻找一种解决方案来引用基本 yaml 的同一数组中的多个文件。 因此有下面的解决方案。 该解决方案不支持递归引用。 它仅支持基本 yaml 中引用的给定目录级别中的通配符。
使用
Adding on @Joshbode's initial answer above , I modified the snippet a little to support UNIX style wild card patterns.
I haven't tested in windows though. I was facing an issue of splitting an array in a large yaml across multiple files for easy maintenance and was looking for a solution to refer multiple files within a same array of the base yaml. Hence the below solution. The solution does not support recursive reference. It only supports wildcards in a given directory level referenced in the base yaml.
Usage
根据之前的帖子:
Based on previous posts:
当提出问题时,可能不支持它,但您可以将其他 YAML 文件导入其中:
虽然我没有任何在线参考,但这对我有用。
Probably it was not supported when question was asked but you can import other YAML file into one:
Though I don't have any online reference but this works for me.
据我所知,YAML 不直接支持包含,您必须自己提供一种机制,但这通常很容易做到。
我在我的 python 应用程序中使用 YAML 作为配置语言,在这种情况下经常定义这样的约定:
然后在我的(python)代码中我这样做:
唯一的缺点是包含中的变量将始终覆盖包含中的变量main,并且无法通过更改“includes: 语句在 main.yml 文件中出现的位置来更改该优先级。
稍有不同的是,YAML 不支持 include,因为它并不是真正设计为像文件一样排他性如果您在 AJAX 请求的响应中得到包含,那么它意味着什么?
Includes are not directly supported in YAML as far as I know, you will have to provide a mechanism yourself however, this is generally easy to do.
I have used YAML as a configuration language in my python apps, and in this case often define a convention like this:
Then in my (python) code I do:
The only down side is that variables in the includes will always override the variables in main, and there is no way to change that precedence by changing where the "includes: statement appears in the main.yml file.
On a slightly different point, YAML doesn't support includes as its not really designed as as exclusively as a file based mark up. What would an include mean if you got it in a response to an AJAX request?
扩展 @Josh_Bode 的答案,这是我自己的 PyYAML 解决方案,它的优点是成为 yaml.Loader 的独立子类。 它不依赖于任何模块级全局变量,也不依赖于修改
yaml
模块的全局状态。Expanding on @Josh_Bode's answer, here's my own PyYAML solution, which has the advantage of being a self-contained subclass of
yaml.Loader
. It doesn't depend on any module-level globals, or on modifying the global state of theyaml
module.使用 Yglu,您可以导入其他文件,如下所示:
A.yaml
B.yaml
由于
$import
是一个函数,您还可以传递一个表达式作为参数:这将给出与上面相同的输出。
免责声明:我是 Yglu 的作者。
With Yglu, you can import other files like this:
A.yaml
B.yaml
As
$import
is a function, you can also pass an expression as argument:This would give the same output as above.
Disclaimer: I am the author of Yglu.
标准 YAML 1.2 本身不包含此功能。 然而,许多实现提供了一些扩展来做到这一点。
我提出了一种使用 Java 和
snakeyaml:1.24
(用于解析/发出 YAML 文件的 Java 库)实现此目标的方法,该方法允许创建自定义 YAML 标记来实现以下目标(您将看到我正在使用它加载在多个 YAML 文件中定义的测试套件,并且我使其作为目标test:
节点的包含列表工作):这是允许处理
的单类 Java !include
标签。 文件从类路径(Maven 资源目录)加载:Standard YAML 1.2 doesn't include natively this feature. Nevertheless many implementations provides some extension to do so.
I present a way of achieving it with Java and
snakeyaml:1.24
(Java library to parse/emit YAML files) that allows creating a custom YAML tag to achieve the following goal (you will see I'm using it to load test suites defined in several YAML files and that I made it work as a list of includes for a targettest:
node):Here is the one-class Java that allows processing the
!include
tag. Files are loaded from classpath (Maven resources directory):不幸的是,YAML 并没有在其标准中提供这一点。
但如果您使用 Ruby,那么有一个 gem 通过扩展 ruby YAML 库来提供您所需的功能:
https://github.com/entwanderer/yaml_extend
Unfortunately YAML doesn't provide this in its standard.
But if you are using Ruby, there is a gem providing the functionality you are asking for by extending the ruby YAML library:
https://github.com/entwanderer/yaml_extend
使用 Symfony,它对 yaml 的处理将间接允许您嵌套 yaml 文件。 诀窍是利用
parameters
选项。 例如:common.yml
config.yml
结果将与以下内容相同:
With Symfony, its handling of yaml will indirectly allow you to nest yaml files. The trick is to make use of the
parameters
option. eg:common.yml
config.yml
The result will be the same as:
我认为@maxy-B 使用的解决方案看起来很棒。 然而,对于我来说,嵌套包含物并没有成功。 例如,如果 config_1.yaml 包含 config_2.yaml,而 config_2.yaml 包含 config_3.yaml,则加载程序出现问题。 但是,如果您只是在加载时将新的加载器类指向其自身,那么它就可以工作! 具体来说,如果我们用稍微修改过的版本替换旧的 _include 函数:
经过反思,我同意其他评论,嵌套加载通常不适合 yaml,因为输入流可能不是文件,但它非常有用!
I think the solution used by @maxy-B looks great. However, it didn't succeed for me with nested inclusions. For example if config_1.yaml includes config_2.yaml, which includes config_3.yaml there was a problem with the loader. However, if you simply point the new loader class to itself on load, it works! Specifically, if we replace the old _include function with the very slightly modified version:
Upon reflection I agree with the other comments, that nested loading is not appropriate for yaml in general as the input stream may not be a file, but it is very useful!
我举几个例子供大家参考。
输出
Update 2
,你可以将它组合起来,就像这样
I make some examples for your reference.
output
Update 2
and you can combine it, like this
您的问题并不要求 Python 解决方案,但这里是使用 PyYAML 的解决方案。
PyYAML 允许您将自定义构造函数(例如
!include
)附加到 YAML 加载器。 我已经包含了一个可以设置的根目录,以便该解决方案支持相对和绝对文件引用。基于类的解决方案
这是一个基于类的解决方案,它避免了我原始响应的全局根变量。
请参阅此 gist,了解类似、更强大的 Python 3 解决方案,该解决方案使用元类来注册自定义构造函数。
示例:
foo.yaml
bar.yaml
现在可以使用以下方式加载文件:
Your question does not ask for a Python solution, but here is one using PyYAML.
PyYAML allows you to attach custom constructors (such as
!include
) to the YAML loader. I've included a root directory that can be set so that this solution supports relative and absolute file references.Class-Based Solution
Here is a class-based solution, that avoids the global root variable of my original response.
See this gist for a similar, more robust Python 3 solution that uses a metaclass to register the custom constructor.
An example:
foo.yaml
bar.yaml
Now the files can be loaded using:
对于 Python 用户,您可以尝试 pyyaml-include。
安装
用法
考虑我们有这样的 YAML 文件:
1.yaml
的内容:2.yaml
的内容:按名称包含文件
在顶层:
如果
0.yaml
是:我们将得到:
在映射中:
如果
0.yaml
是:我们将得到:
按顺序:
>
如果
0.yaml
是:我们将得到:
通过通配符包含
文件 文件名可以包含 shell 样式的通配符。 从通配符找到的文件加载的数据将按顺序设置。
如果
0.yaml
是:我们将得到:
为了启用
recursive
参数,我们应该在Mapping
或Sequence
模式下编写!include
标签:Sequence
模式:Mapping
模式下的参数:For Python users, you can try pyyaml-include.
Install
Usage
Consider we have such YAML files:
1.yaml
's content:2.yaml
's content:Include files by name
On top level:
If
0.yaml
was:We'll get:
In mapping:
If
0.yaml
was:We'll get:
In sequence:
If
0.yaml
was:We'll get:
Include files by wildcards
File name can contain shell-style wildcards. Data loaded from the file(s) found by wildcards will be set in a sequence.
If
0.yaml
was:We'll get:
In order to enable
recursive
argument, we shall write the!include
tag inMapping
orSequence
mode:Sequence
mode:Mapping
mode:YML 标准没有指定执行此操作的方法。 而且这个问题并不局限于 YML。 JSON 也有同样的限制。
许多使用基于 YML 或 JSON 的配置的应用程序最终都会遇到这个问题。 当这种情况发生时,他们会制定自己的惯例。
例如,对于 swagger API 定义:
例如,对于 docker compose 配置:
或者,如果您想将 yml 文件的内容拆分为多个文件(如内容树),您可以定义自己的文件夹结构约定并使用(现有的) 合并脚本。
The YML standard does not specify a way to do this. And this problem does not limit itself to YML. JSON has the same limitations.
Many applications which use YML or JSON based configurations run into this problem eventually. And when that happens, they make up their own convention.
e.g. for swagger API definitions:
e.g. for docker compose configurations:
Alternatively, if you want to split up the content of a yml file in multiple files, like a tree of content, you can define your own folder-structure convention and use an (existing) merge script.
不,标准 YAML 不包含任何类型的“导入”或“包含”语句。
No, standard YAML does not include any kind of "import" or "include" statement.