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


94

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

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规范进行了搜索,但找不到任何内容,因此我怀疑答案只是“不,你不能这样做”。但是,如果有人有什么好主意。


编辑:由于没有答案,我假设没有人发现我在YAML规范中没有的任何东西,而这不能在YAML层完成。因此,我正在提出一个问题,以便对YAML进行后处理以帮助解决此问题,以防将来有人发现此问题。


注意:也可以通过在YAML中标准使用锚定和别名来解决此问题。另请参阅: 如何合并YAML数组?
dreftymac

Answers:


53

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

重要的是要注意它与映射一起使用,而不是序列作为您的第一个示例。当您考虑它时,这是有道理的,并且您的示例似乎也不一定需要是连续的。只需将序列值更改为映射键即可解决问题,如以下(未经测试的)示例所示:

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

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


啊,谢谢你!这很有帮助。遗憾的是,它不适用于序列。没错,顺序对于此示例并不重要;从概念上讲,我所拥有的是一个集合,但它比序列更紧密地映射到序列。而我得到的结果的结构很重要(这就是为什么我不想只添加另一层嵌套来合并我的结构),所以有一个我需要忽略(所有null)值的映射不会真的不行。

3
在当前的官方YAML规范中,我看不到任何内容:yaml.org/spec/1.2/spec.html。该页面不包含单词“ merge”,文本“ <<”或短语“ key type”。<<语法在Python yaml包中确实起作用。您知道在哪里可以找到有关这些额外功能的更多信息吗?
2012年

1
它不是直接在规范中,而是在标记存储库中进行了描述。其他架构具有一般说明和链接。除了合并键外,还有集合和有序集合。但是,YAML将集合视为一种映射类型(例如,以上示例可以实现为集合)。您的语言是否允许您在结果映射中将键与值交换?即使您必须自己实现,我认为它也会更干净。您至少已经将所有数据组合在一起,并且您的YAML是标准的。
kittemon 2012年

集合不是映射。映射是一组键值关联。当我yaml.load(...)使用Python时,我得到一个字典作为YAML映射的表示形式。是的,将其后处理为集合很容易,但是我必须知道这种情况已经发生了(并且如果规则是“集合写为具有空值的映射”,则读/写配置文件时的语义复杂性会更高。 )。鉴于yaml.load(...)无论是否使用<<MERGE,我都需要在和使用结果数据之间进行后处理,因此我可能会坚持使用MERGE(现在已经实现了)。
2012年

2
是的,我确实找到了那个!!set作品。虽然太模糊了样板。这些文件由不一定是YAML专家的人员制成,以便于人类可读/可写。人们将把他们的网站列表记为YAML列表,然后要合并它们,并且必须将整个内容转换为集合,并记住将其明确标记为集合...我还有其他一些标准化的MERGE无论如何处理事物。谢谢您的帮助!
2012年

16

正如前面的答案所指出的那样,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实现了这个功能,并在这里发布

请享用!


2
注意:也可以通过在YAML中标准使用锚定和别名来解决此问题。另请参阅: 如何合并YAML数组?
dreftymac

11
这是否意味着该方法仅适用于合并sites和的单独工具sites+。我的意思是必须由用户实施的工具,因为这不是默认yaml行为吗?
stan0

7

(回答我自己的问题,以防万一我使用的解决方案对以后搜索此问题的人有用)

没有纯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解析器从配置文件中获取本机对象之后,但在将对象传递给应用程序的其余部分之前,我的应用程序将遍历对象图以查找包含单个键的映射MERGE。与相关联的值MERGE必须是列表列表或地图列表;其他任何子结构都是错误。

在列表列表的情况下,包含的整个地图MERGE将被按其出现顺序连接在一起的子列表替换。

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

上面给出的示例并不是那么有用,因为您可以直接编写所需的结构。它更可能显示为:

foo:
  MERGE:
    - *salt
    - *pepper

允许您创建包含节点中所有内容saltpepper在其他位置使用的列表或地图。

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


6

为了从这里的两个答案中弄清楚一些内容,列表的YAML不直接支持此功能(但字典支持此功能,请参见kittemon的答案)。


注意:也可以通过在YAML中标准使用锚定和别名来解决此问题。另请参阅: 如何合并YAML数组?
dreftymac

5

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

foo:
    << : myanchor
    bar:
    baz:

而不是建议的语法

foo:
    << : myanchor
    ? bar
    ? baz

就像Kittemon的建议一样,这将使您可以使用引用在映射中定位锚,并避免序列问题。在发现Symfony Yaml组件v2.4.4不会重新组织? bar语法后,我发现自己需要这样做。


哪些呢myanchor样子?
ssc
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.