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

时间:2012-02-13 00:37:10

标签: arrays dictionary yaml cross-reference

所以,我知道我可以这样做:

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

anotherlist: *sites

sitelistanotherlist都包含www.foo.comwww.bar.com。但是,我真正想要的是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处理,例如实现变量替换或自动提升某些类型的子结构?我已经在进行那种后处理来处理其他一些用例,所以我并不完全厌恶它。但我的YAML文件将由人类编写,而不是由机器生成,因此我希望尽量减少用户在标准YAML语法之上需要记忆的规则数量。

我也希望能够用地图做类似的事情:

namedsites: &sites
  Foo: www.foo.com
  Bar: www.bar.com

moresites: *sites
  Baz: www.baz.com

我通过YAML spec进行了搜索,找不到任何内容,所以我怀疑答案只是“不,你不能这样做”。但是,如果有人有任何想法会很棒。


编辑:由于没有答案,我假设没有人发现我在YAML规范中没有的任何内容,并且这不能在YAML层完成。所以我打开了一个问题,想要对YAML进行后处理以帮助解决这个问题,以防将来有人发现这个问题。

5 个答案:

答案 0 :(得分:48)

The merge key type可能就是你想要的。它使用特殊的<<映射键来指示合并,允许将映射(或一系列此类别名)的别名用作初始化器以合并到单个映射中。此外,您仍然可以显式覆盖值,或添加合并列表中不存在的更多值。

重要的是要注意它适用于映射,而不是序列作为您的第一个示例。当你考虑它时,这是有道理的,你的例子看起来可能不需要顺序。只需将序列值更改为映射键即可,如下所示(未经测试)示例:

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

有些事情需要注意。首先,由于<<是一个密钥,因此每个节点只能指定一次。其次,当使用序列作为值时,顺序是重要的。这在这里的示例中无关紧要,因为没有关联的值,但值得注意。

答案 1 :(得分:14)

正如之前的答案所指出的,没有内置支持在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

这个想法是将一个键结尾的内容合并到&#39; +&#39;没有&#39; +&#39;到相应的密钥。我在Python中实现了它并发布了https://developer.apple.com/reference/foundation/nscache?language=objc

享受!

答案 2 :(得分:6)

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

答案 3 :(得分:4)

(回答我自己的问题,以防我使用的解决方案对将来搜索此内容的人有用)

由于没有纯YAML方法,我将把它实现为YAML解析器和实际使用配置文件的代码之间的“语法转换”。因此,我的核心应用程序根本不必担心任何人性化的冗余避免措施,并且可以直接对结果结构采取行动。

我要使用的结构如下:

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

更正式地说,在调用YAML解析器从配置文件中获取本机对象之后,但在将对象传递给应用程序的其余部分之前,我的应用程序将遍历对象图,寻找包含单个键{{1}的映射}。与MERGE关联的值必须是列表列表或地图列表;任何其他子结构都是错误的。

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

在地图列表的情况下,包含MERGE的整个地图将被包含子地图中所有键/值对的单个地图替换。如果键中存在重叠,则将使用MERGE列表中最后出现的子映射的值。

上面给出的例子没那么有用,因为你可以直接编写你想要的结构。它更有可能显示为:

MERGE

允许您创建包含在其他地方使用的节点foo: MERGE: - *salt - *pepper salt中的所有内容的列表或地图。

(我一直在提供pepper外部地图,以表明foo:必须是其映射中的唯一键,这意味着MERGE无法显示为顶级名称,除非没有其他顶级名称)

答案 4 :(得分:4)

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

foo:
    << : myanchor
    bar:
    baz:

而不是建议的语法

foo:
    << : myanchor
    ? bar
    ? baz

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