是否有共享列表或地图的一部分的YAML语法?

所以,我知道我可以做这样的事情:

sitelist: &sites - www.foo.com - www.bar.com anotherlist: *sites 

并且有网站anotherlistanotherlist都包含www.foo.comanotherlist 。 但是,我真正想要的是anotherlist 包含www.baz.com ,而不必重复www.foo.comwww.baz.com

这样做给了我在YAML分析器中的语法错误:

 sitelist: &sites - www.foo.com - www.bar.com anotherlist: *sites - www.baz.com 

只要使用锚和别名,似乎不可能做我想要的,而不增加另一层子结构,如:

 sitelist: &sites - www.foo.com - www.bar.com anotherlist: - *sites - www.baz.com 

这意味着这个YAML文件的使用者必须意识到这一点。

有没有一种纯粹的YAML做这样的事情? 或者我将不得不使用一些YAML后处理,例如实现某些子结构的variablesreplace或自动提升? 我已经在做这种后处理来处理其他一些用例,所以我并不完全反对。 但是我的YAML文件将被人类编写,而不是机器生成的,所以我想在标准YAML语法的基础上尽量减less我的用户需要记住的规则的数量。

我也想用地图做类似的事情:

 namedsites: &sites Foo: www.foo.com Bar: www.bar.com moresites: *sites Baz: www.baz.com 

我已经通过YAML规范search,找不到任何东西,所以我怀疑答案只是“不,你不能这样做”。 但是,如果有人有任何想法,将是伟大的。


编辑:由于没有答案,我假设没有人发现任何我没有在YAML规范,这不能在YAML层完成。 所以我打开这个问题来想想后期处理YAML来帮助解决这个问题,以防将来有人发现这个问题。

合并密钥types可能是你想要的。 它使用一个特殊的<<映射关键字来表示合并,允许一个映射的别名(或者这样的别名序列)被用作一个初始化器来合并成一个映射。 此外,您仍然可以显式重写值,或者添加更多不存在于合并列表中的值。

重要的是要注意,它与映射一起工作,而不是序列作为第一个例子。 这是有道理的,当你考虑它,你的例子看起来可能不需要按顺序。 简单地改变你的序列值到映射键应该做的伎俩,如下面(未经testing)的例子:

 sitelist: &sites ? www.foo.com # "www.foo.com" is the key, the value is null ? www.bar.com anotherlist: << : *sites # merge *sites into this mapping ? www.baz.com # add extra stuff 

有些事情要注意。 首先,由于<<是一个关键,因此每个节点只能指定一次。 其次,当使用序列作为值时,顺序是显着的。 这里没有关系,因为没有关联的值,但值得注意。

(回答我自己的问题,以防万一我使用的解决scheme对于将来search这个的人有用)

由于没有使用纯YAML的方法,所以我将把它作为一个位于YAMLparsing器和实际使用configuration文件的代码之间的“语法转换”来实现。 因此,我的核心应用程序不必担心任何人性化的冗余避免措施,并可以直接对结果进行操作。

我要使用的结构如下所示:

 foo: MERGE: - - a - b - c - - 1 - 2 - 3 

这将转化为相当于:

 foo: - a - b - c - 1 - 2 - 3 

或者,用地图:

 foo: MERGE: - fork: a spoon: b knife: c - cup: 1 mug: 2 glass: 3 

将被转换为:

 foo: fork: a spoon: b knife: c cup: 1 mug: 2 glass: 3 

更正式地说,在调用YAMLparsing器从configuration文件中获取本地对象之后,在将对象传递给应用程序的其余部分之后,我的应用程序将遍历对象图,查找包含单个键MERGE映射。 与MERGE相关联的值必须是列表的列表或地图列表; 任何其他子结构是一个错误。

在list-of-lists的情况下,包含MERGE的整个地图将被replace为按照它们出现的顺序连接在一起的子列表。

在地图列表的情况下,包含MERGE的整个地图将由包含子地图中的所有键/值对的单个地图replace。 在键中有重叠的地方,将使用最后在MERGE列表中出现的子地图的值。

上面的例子没有用,因为你可以直接写出你想要的结构。 这更可能performance为:

 foo: MERGE: - *salt - *pepper 

允许您创build一个列表或地图,其中包含节点saltpepper在其他地方使用的所有内容。

(我一直给这个foo: outer map来表明MERGE必须是它映射中的唯一键,这意味着MERGE不能出现在顶级名字上,除非没有其他的顶级名字)

要搭载Kittemon的答案,请注意,您可以使用替代语法创build具有空值的映射

 foo: << : myanchor bar: baz: 

而不是build议的语法

 foo: << : myanchor ? bar ? baz 

像Kittemon的build议一样,这将允许您在映射中使用对锚点的引用并避免序列问题。 发现Symfony Yaml组件v2.4.4没有logging下来,我发现自己需要这样做? bar ? bar语法。

为了澄清这里的两个答案,YAML不直接支持列表(但它支持字典,请参阅kittemon的答案)。

正如前面的答案所指出的那样,在YAML中没有内置的扩展列表支持。 我提供了另一种自己实现的方法。 考虑一下:

 defaults: &defaults sites: - www.foo.com - www.bar.com setup1: <<: *defaults sites+: - www.baz.com 

这将被处理成:

 defaults: sites: - www.foo.com - www.bar.com setup1: sites: - www.foo.com - www.bar.com - www.baz.com 

这个想法是把一个以'+'结尾的密钥的内容合并到没有'+'的对应密钥。 我用Python实现了这个,并在这里发布。

请享用!