Ben*_*Ben 81 arrays dictionary yaml cross-reference
所以,我知道我可以这样做:
sitelist: &sites
- www.foo.com
- www.bar.com
anotherlist: *sites
Run Code Online (Sandbox Code Playgroud)
并拥有sitelist和anotherlist都包含www.foo.com和www.bar.com.不过,我真正想要的是anotherlist对还包含www.baz.com,而无需重复www.foo.com和www.baz.com.
这样做会在YAML解析器中出现语法错误:
sitelist: &sites
- www.foo.com
- www.bar.com
anotherlist: *sites
- www.baz.com
Run Code Online (Sandbox Code Playgroud)
只使用锚和别名,似乎不可能做我想要的而不添加另一级子结构,例如:
sitelist: &sites
- www.foo.com
- www.bar.com
anotherlist:
- *sites
- www.baz.com
Run Code Online (Sandbox Code Playgroud)
这意味着此YAML文件的使用者必须了解它.
有一种纯粹的YAML方式做这样的事情吗?或者我是否必须使用一些后YAML处理,例如实现变量替换或自动提升某些类型的子结构?我已经在进行那种后处理来处理其他一些用例,所以我并不完全厌恶它.但我的YAML文件将由人类编写,而不是由机器生成,因此我希望尽量减少用户在标准YAML语法之上需要记忆的规则数量.
我也希望能够用地图做类似的事情:
namedsites: &sites
Foo: www.foo.com
Bar: www.bar.com
moresites: *sites
Baz: www.baz.com
Run Code Online (Sandbox Code Playgroud)
我有一个搜索YAML规范,但找不到任何东西,所以我怀疑答案只是"不,你不能这样做".但是,如果有人有任何想法会很棒.
编辑:由于没有答案,我假设没有人发现我在YAML规范中没有的任何东西,并且这不能在YAML层完成.所以我打开了一个问题,想要对YAML进行后处理以帮助解决这个问题,以防将来有人发现这个问题.
kit*_*mon 49
合并密钥类型可能是您想要的.它使用特殊的<<映射键来指示合并,允许将映射(或一系列此类别名)的别名用作初始化器以合并到单个映射中.此外,您仍然可以显式覆盖值,或添加合并列表中不存在的更多值.
重要的是要注意它适用于映射,而不是序列作为您的第一个示例.当你考虑它时,这是有道理的,你的例子看起来可能不需要顺序.只需将序列值更改为映射键即可,如下所示(未经测试)示例:
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
Run Code Online (Sandbox Code Playgroud)
有些事情需要注意.首先,因为<<是密钥,所以每个节点只能指定一次.其次,当使用序列作为值时,顺序是重要的.这在这里的示例中无关紧要,因为没有关联的值,但值得注意.
Ale*_*hov 17
正如之前的答案所指出的,没有内置支持在YAML中扩展列表.我提供了另一种自己实现它的方法.考虑一下:
defaults: &defaults
sites:
- www.foo.com
- www.bar.com
setup1:
<<: *defaults
sites+:
- www.baz.com
Run Code Online (Sandbox Code Playgroud)
这将被处理成:
defaults:
sites:
- www.foo.com
- www.bar.com
setup1:
sites:
- www.foo.com
- www.bar.com
- www.baz.com
Run Code Online (Sandbox Code Playgroud)
我们的想法是将一个以"+"结尾的键的内容合并到相应的键而不使用"+".我在Python中实现了这个并在这里发布 .
请享用!
(回答我自己的问题,以防我使用的解决方案对将来搜索此问题的任何人有用)
由于没有纯 YAML 方法可以做到这一点,我将把它实现为位于 YAML 解析器和实际使用配置文件的代码之间的“语法转换”。所以我的核心应用程序根本不必担心任何人性化的冗余避免措施,并且可以直接对结果结构采取行动。
我要使用的结构如下所示:
foo:
MERGE:
- - a
- b
- c
- - 1
- 2
- 3
Run Code Online (Sandbox Code Playgroud)
这将转换为等效于:
foo:
- a
- b
- c
- 1
- 2
- 3
Run Code Online (Sandbox Code Playgroud)
或者,使用地图:
foo:
MERGE:
- fork: a
spoon: b
knife: c
- cup: 1
mug: 2
glass: 3
Run Code Online (Sandbox Code Playgroud)
将转换为:
foo:
fork: a
spoon: b
knife: c
cup: 1
mug: 2
glass: 3
Run Code Online (Sandbox Code Playgroud)
更正式地说,在调用 YAML 解析器从配置文件中获取本机对象之后,但在将对象传递给应用程序的其余部分之前,我的应用程序将遍历对象图以寻找包含单个键的映射MERGE。关联的值MERGE必须是列表列表或映射列表;任何其他子结构都是错误的。
在列表列表的情况下,包含的整个地图MERGE将被按照它们出现的顺序连接在一起的子列表替换。
在映射列表的情况下,包含的整个映射MERGE将被包含子映射中所有键/值对的单个映射替换。如果键有重叠,MERGE将使用列表中最后出现的子映射中的值。
上面给出的示例并不是那么有用,因为您可以直接编写您想要的结构。它更有可能显示为:
foo:
MERGE:
- *salt
- *pepper
Run Code Online (Sandbox Code Playgroud)
允许您创建包含节点中所有内容salt并pepper在其他地方使用的列表或地图。
(我一直给那个foo:外部映射以表明它MERGE必须是其映射中的唯一键,这意味着它MERGE不能作为顶级名称出现,除非没有其他顶级名称)
小智 5
要利用 Kittemon 的答案,请注意您可以使用替代语法创建具有空值的映射
foo:
<< : myanchor
bar:
baz:
Run Code Online (Sandbox Code Playgroud)
而不是建议的语法
foo:
<< : myanchor
? bar
? baz
Run Code Online (Sandbox Code Playgroud)
就像 Kittemon 的建议一样,这将允许您在映射中使用对锚点的引用并避免序列问题。在发现 Symfony Yaml 组件 v2.4.4 无法识别? bar语法后,我发现自己需要这样做。