Is there YAML syntax for sharing part of a list or map?

前端 未结 5 2133
猫巷女王i
猫巷女王i 2020-11-29 01:07

So, I know I can do something like this:

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

anotherlist: *sites

And have sitelist<

相关标签:
5条回答
  • 2020-11-29 01:21

    The merge key type is probably what you want. It uses a special << mapping key to indicate merges, allowing an alias to a mapping (or a sequence of such aliases) to be used as an initializer to merge into a single mapping. Additionally, you can still explicitly override values, or add more that weren't present in the merge list.

    It's important to note that it works with mappings, not sequences as your first example. This makes sense when you think about it, and your example looks like it probably doesn't need to be sequential anyway. Simply changing your sequence values to mapping keys should do the trick, as in the following (untested) example:

    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
    

    Some things to notice. Firstly, since << is a key, it can only be specified once per node. Secondly, when using a sequence as the value, the order is significant. This doesn't matter in the example here, since there aren't associated values, but it's worth being aware.

    0 讨论(0)
  • 2020-11-29 01:25

    To clarify something from the two answers here, this is not supported directly in YAML for lists (but it is supported for dictionaries, see kittemon's answer).

    0 讨论(0)
  • 2020-11-29 01:28

    To piggyback off of Kittemon's answer, note that you can create mappings with null values using the alternative syntax

    foo:
        << : myanchor
        bar:
        baz:
    

    instead of the suggested syntax

    foo:
        << : myanchor
        ? bar
        ? baz
    

    Like Kittemon's suggestion, this will allow you to use references to anchors within the mapping and avoid the sequence issue. I found myself needing to do this after discovering that the Symfony Yaml component v2.4.4 doesn't recorgnize the ? bar syntax.

    0 讨论(0)
  • 2020-11-29 01:31

    As the previous answers have pointed out, there is no built-in support for extending lists in YAML. I am offering yet another way to implement it yourself. Consider this:

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

    This will be processed into:

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

    The idea is to merge the contents of a key ending with a '+' to the corresponding key without a '+'. I implemented this in Python and published here.

    Enjoy!

    0 讨论(0)
  • 2020-11-29 01:31

    (Answering my own question in case the solution I'm using is useful for anyone who searches for this in future)

    With no pure-YAML way to do this, I'm going to implement this as a "syntax transformation" sitting between the YAML parser and the code that actually uses the configuration file. So my core application doesn't have to worry at all about any human-friendly redundancy-avoidance measures, and can just act directly on the resulting structures.

    The structure I'm going to use looks like this:

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

    Which would be transformed to the equivalent of:

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

    Or, with maps:

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

    Would be transformed to:

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

    More formally, after calling the YAML parser to get native objects from a config file, but before passing the objects to the rest of the application, my application will walk the object graph looking for mappings containing the single key MERGE. The value associated with MERGE must be either a list of lists, or a list of maps; any other substructure is an error.

    In the list-of-lists case, the entire map containing MERGE will be replaced by the child lists concatenated together in the order they appeared.

    In the list-of-maps case, the entire map containing MERGE will be replaced by a single map containing all of the key/value pairs in the child maps. Where there is overlap in the keys, the value from the child map occurring last in the MERGE list will be used.

    The examples given above are not that useful, since you could have just written the structure you wanted directly. It's more likely to appear as:

    foo:
      MERGE:
        - *salt
        - *pepper
    

    Allowing you to create a list or map containing everything in nodes salt and pepper being used elsewhere.

    (I keep giving that foo: outer map to show that MERGE must be the only key in its mapping, which means that MERGE cannot appear as a top-level name unless there are no other top level names)

    0 讨论(0)
提交回复
热议问题