这是行不通的:
-
合并仅受 YAML 规范的映射支持,不支持序列
-
您通过合并键 << 完全混合了事物
后跟键/值分隔符: 和一个值
参考 ,然后在同一缩进处继续列表
等级
这不是正确的 YAML:
combine_stuff:
x: 1
- a
- b
所以你的示例语法作为 YAML 扩展提案甚至没有意义。
如果您想执行合并多个数组之类的操作,您可能需要考虑如下语法:
combined_stuff:
- <<: *s1, *s2
- <<: *s3
- d
- e
- f
其中s1、s2、s3 是序列上的锚点(未显示),您
想要合并成一个新的序列,然后有d、e和f
附加到那个。但是 YAML 正在解决这种结构深度
首先,因此在处理过程中没有可用的真实上下文
的合并键。您在哪里没有可用的数组/列表
可以将处理后的值(锚定序列)附加到。
您可以采用@dreftymac 提出的方法,但这有一个巨大的缺点,即您
不知何故需要知道要展平哪些嵌套序列(即通过知道根的“路径”
加载的数据结构到父序列),或者您递归地遍历加载的
搜索嵌套数组/列表的数据结构,并不加选择地将它们全部展平。
IMO 更好的解决方案是使用标签来加载数据结构
为你做扁平化。这允许清楚地表示什么
需要展平,什么不需要,让你完全控制
这种展平是在加载期间完成还是在加载期间完成
使用权。选择哪一个是易于实施和
时间和存储空间的效率。这是同样需要做出的权衡
用于实施merge key feature 和
没有单一的解决方案永远是最好的。
例如我的ruamel.yaml 库在
使用其安全加载器时加载,导致合并
是普通 Python 字典的字典。必须完成此合并
前期,并复制数据(空间效率低下),但价值很快
抬头。使用往返加载程序时,您希望能够转储
合并未合并,因此需要将它们分开。字典喜欢
由于往返加载而加载的数据结构是空间
高效但访问速度较慢,因为它需要尝试查找密钥
在合并中的字典本身中找不到(并且没有缓存,所以
每次都需要这样做)。当然这样的考虑是
对于相对较小的配置文件不是很重要。
以下使用带有标签flatten的对象在python中为列表实现类似合并的方案
它即时递归到列表项并标记为toflatten。使用这两个标签
你可以有 YAML 文件:
l1: &x1 !toflatten
- 1
- 2
l2: &x2
- 3
- 4
m1: !flatten
- *x1
- *x2
- [5, 6]
- !toflatten [7, 8]
(使用流与块样式序列完全是任意的,对
加载结果)。
当迭代作为键 m1 的值的项目时
“递归”到标记有toflatten 的序列中,但显示
其他列表(无论是否有别名)作为单个项目。
使用 Python 代码实现这一目标的一种可能方法是:
import sys
from pathlib import Path
import ruamel.yaml
yaml = ruamel.yaml.YAML()
@yaml.register_class
class Flatten(list):
yaml_tag = u'!flatten'
def __init__(self, *args):
self.items = args
@classmethod
def from_yaml(cls, constructor, node):
x = cls(*constructor.construct_sequence(node, deep=True))
return x
def __iter__(self):
for item in self.items:
if isinstance(item, ToFlatten):
for nested_item in item:
yield nested_item
else:
yield item
@yaml.register_class
class ToFlatten(list):
yaml_tag = u'!toflatten'
@classmethod
def from_yaml(cls, constructor, node):
x = cls(constructor.construct_sequence(node, deep=True))
return x
data = yaml.load(Path('input.yaml'))
for item in data['m1']:
print(item)
哪个输出:
1
2
[3, 4]
[5, 6]
7
8
如您所见,在需要展平的序列中,您
可以使用标记序列的别名,也可以使用标记序列
顺序。 YAML 不允许您这样做:
- !flatten *x2
,即标记一个
锚定序列,因为这本质上会使它变成一个不同的
数据结构。
使用 explicit 标签比使用一些魔法更好
使用 YAML 合并键 <<。如果没有别的,你现在必须经历
如果您碰巧有一个 YAML 文件,该文件的映射具有键
<< 你不想表现得像一个合并键,例如当你做一个
将 C 运算符映射到英语(或其他一些自然语言)的描述。