Skip to content

yaml merge Anchor Options

William W. Kimball, Jr., MBA, MSIS edited this page May 22, 2021 · 24 revisions
  1. Introduction
  2. Scalar Anchors
    1. Left Scalar Anchor Override
    2. Right Scalar Anchor Override
    3. Rename Conflicting Scalar Anchors
  3. Hash Anchors
    1. Left Hash Anchor Override
    2. Right Hash Anchor Override
    3. Rename Conflicting Hash Anchors
  4. Configuration File Options
    1. Configuration File Section: defaults
    2. Configuration File Section: rules

This document is part of the body of knowledge about yaml-merge, one of the reference command-line tools provided by the YAML Path project.

Introduction

The yaml-merge command-line tool enables users to control how it handles conflicting Anchors during a merge operation. Non-conflicting Anchors are automatically merged and the definition-use order between each Anchor and its Aliases is preserved during the merge. An Anchor conflict occurs only when the same Anchor name is used in both of the LHS and RHS documents and the Anchored value is different between them.

Any attempt to merge with Anchor conflicts when using default options will result in an error. This is because the yaml-merge tool will refuse any operation which would destroy data unless the user explicitly instructs it to do so, and how. Not all Anchor conflict resolution options are destructive; the rename option preserves all Anchors and their Aliases in both documents by uniquely renaming conflicting Anchors and Aliases in the RHS document.

But what are Anchors? In short:

Anchors are a name assigned to a Scalar or Hash (AKA: Map, Dictionary) YAML data element. This name is prefixed with an & sign. Beyond that point within the same YAML document, the data which was "anchored" can be re-used any number of times by referencing the Anchor via its Alias form whereby the & is replaced with an * sign.

In other words, YAML defines two kinds of Anchors. Scalar Anchors define reusable Scalar values (which are String, Integer, Float, Boolean, etc. data types). Hash Anchors (AKA Map Anchors or Dictionary Anchors) define a reusable set of key-value pairs which can be merged into other Hashes within the same document using their YAML Merge Keys (<<:). To date, there is no definition in YAML for an Array Anchor (AKA List Anchor or Sequence Anchor).

Each of these Anchor types will be explored in how they are merged based on user option selection. When there is no conflict, RHS Anchors are merged into the LHS document no matter what Anchor merge option is selected. In order to resolve Anchor conflicts, the yaml-merge tool's available Anchor merge options include:

  1. stop (the default) causes merging to abort upon detection of an Anchor conflict.
  2. left causes LHS Anchors to overwrite conflicting RHS Anchors.
  3. right causes RHS Anchors to overwrite conflicting LHS Anchors.
  4. rename causes RHS Anchors to be automatically and uniquely renamed before they are merged into the LHS document. The RHS document is updated to use the new Anchor name everywhere its Aliases appear before the merge.

Scalar Anchors

Scalar Anchors create a single value which can be reused in multiple places within the same YAML document. This enables YAML file authors to institute "One Version of the Truth", enabling a change in exactly one place to affect an identical change everywhere that same change is needed. By convention, they are usually gathered up into a special Array named aliases: near the top of each YAML file. Such a file might look like:

File: LHS1.yaml

---
aliases:
  - &scalar_anchor_string This is a reusable String value
  - &scalar_anchor_integer 5280

a_hash:
  which_reuses:
    those_anchors:
      string_alias: *scalar_anchor_string
      integer_alias: *scalar_anchor_integer
  in_several_places:
    string_alias: *scalar_anchor_string
    integer_alias: *scalar_anchor_integer

Were you to query the YAML file at /a_hash/which_reuses/those_anchors/string_alias (or a_hash.which_reuses.those_anchors.string_alias), you'd get back This is a reusable String value:

yaml-get --query=/a_hash/which_reuses/those_anchors/string_alias LHS1.yaml
This is a reusable String value

We can impose an Anchor conflict by attempting to merge with:

File: RHS1.yaml

---
aliases:
  - &scalar_anchor_string A DIFFERENT STRING VALUE
  - &scalar_anchor_integer 5280

another_hash:
  another_alias_string: *scalar_anchor_string
  another_alias_integer: *scalar_anchor_integer

Notice that RHS1.yaml redefines &scalar_anchor_string but not &scalar_anchor_integer. In this case, only &scalar_anchor_string is in conflict. A query against /another_hash/another_alias_string (or another_hash.another_alias_string) in RHS1.yaml would yield the expected value:

yaml-get --query=/another_hash/another_alias_string RHS1.yaml
A DIFFERENT STRING VALUE

The next sub-sections are examples of the various ways to deal with such an Anchor conflict.

Left Scalar Anchor Override

You can instruct yaml-merge to override the value of conflicting Anchors in the RHS document. By setting --anchors=left or -a left, yaml-merge would produce this output:

---
aliases:
  - &scalar_anchor_string This is a reusable String value
  - &scalar_anchor_integer 5280
  - *scalar_anchor_string
  - *scalar_anchor_integer
a_hash:
  which_reuses:
    those_anchors:
      string_alias: *scalar_anchor_string
      integer_alias: *scalar_anchor_integer
  in_several_places:
    string_alias: *scalar_anchor_string
    integer_alias: *scalar_anchor_integer
another_hash:
  another_alias_string: *scalar_anchor_string
  another_alias_integer: *scalar_anchor_integer

Notice that the RHS Anchors were turned into Aliases of the same-named LHS Anchors. Because the default option for Arrays is to preserve all elements from both documents during the merge, the aliases: array receives the redefined Anchors-as-Aliases from the RHS document. This is normal and you can override this behavior.

If you were to repeat the previous two queries against the merged document, and inspect the resulting aliases: Array, you'd get:

yaml-merge --anchors=left LHS1.yaml RHS1.yaml | yaml-get --query=/a_hash/which_reuses/those_anchors/string_alias -
This is a reusable String value

yaml-merge --anchors=left LHS1.yaml RHS1.yaml | yaml-get --query=/another_hash/another_alias_string -
This is a reusable String value

yaml-merge --anchors=left LHS1.yaml RHS1.yaml | yaml-get --query=/aliases -
["This is a reusable String value", 5280, "This is a reusable String value", 5280]

Right Scalar Anchor Override

You can instruct yaml-merge to override the value of conflicting Anchors in the LHS document. By setting --anchors=right or -a right, yaml-merge would produce this output:

---
aliases:
  - &scalar_anchor_string A DIFFERENT STRING VALUE
  - &scalar_anchor_integer 5280
  - *scalar_anchor_string
  - *scalar_anchor_integer
a_hash:
  which_reuses:
    those_anchors:
      string_alias: *scalar_anchor_string
      integer_alias: *scalar_anchor_integer
  in_several_places:
    string_alias: *scalar_anchor_string
    integer_alias: *scalar_anchor_integer
another_hash:
  another_alias_string: *scalar_anchor_string
  another_alias_integer: *scalar_anchor_integer

Notice that the conflicting RHS Anchor (&scalar_anchor_string) has replaced the original LHS value. As with the right behavior and because the default option for Arrays is to preserve all elements from both documents during the merge, the aliases: array again shows the redefined Anchors-as-Aliases from the LHS and RHS documents. This is normal and you can override this behavior.

If you were to repeat the previous two queries against the merged document, and inspect the resulting aliases: Array, you'd get:

yaml-merge --anchors=right LHS1.yaml RHS1.yaml | yaml-get --query=/a_hash/which_reuses/those_anchors/string_alias -
A DIFFERENT STRING VALUE

yaml-merge --anchors=right LHS1.yaml RHS1.yaml | yaml-get --query=/another_hash/another_alias_string -
A DIFFERENT STRING VALUE

yaml-merge --anchors=right LHS1.yaml RHS1.yaml | yaml-get --query=/aliases -
["A DIFFERENT STRING VALUE", 5280, "A DIFFERENT STRING VALUE", 5280]

Rename Conflicting Scalar Anchors

You may not always wish to override the values of Scalar Anchors during a merge. In some cases, such collisions may be accidental and you really need both documents' Anchors to be preserved during the merge. For this and similar cases, yaml-merge supports a rename option for handling Anchor collisions. By setting --anchors=rename or -a rename, yaml-merge would produce this output:

---
aliases:
  - &scalar_anchor_string This is a reusable String value
  - &scalar_anchor_integer 5280
  - &scalar_anchor_string_1 A DIFFERENT STRING VALUE
  - *scalar_anchor_integer
a_hash:
  which_reuses:
    those_anchors:
      string_alias: *scalar_anchor_string
      integer_alias: *scalar_anchor_integer
  in_several_places:
    string_alias: *scalar_anchor_string
    integer_alias: *scalar_anchor_integer
another_hash:
  another_alias_string: *scalar_anchor_string_1
  another_alias_integer: *scalar_anchor_integer

Notice that the conflicting RHS Anchor (&scalar_anchor_string) was renamed to &scalar_anchor_string_1. Throughout the rest of the merged document, all uses of the previously-conflicting Anchor name have been renamed to match this change, fully preserving both the LHS and RHS documents in the merged result. Note also that the non-conflicting anchor (&scalar_anchor_integer) caused no disruption and seamlessly integrated with the LHS original. Because the default option for Arrays is to preserve all elements from both documents during the merge, the aliases: array again shows the redefined Anchor-as-Alias for this non-conflicting element. This is normal and you can override this behavior.

If you were to repeat the previous two queries against the merged document, and inspect the resulting aliases: Array, you'd get:

yaml-merge --anchors=rename LHS1.yaml RHS1.yaml | yaml-get --query=/a_hash/which_reuses/those_anchors/string_alias -
This is a reusable String value

yaml-merge --anchors=rename LHS1.yaml RHS1.yaml | yaml-get --query=/another_hash/another_alias_string -
A DIFFERENT STRING VALUE

yaml-merge --anchors=rename LHS1.yaml RHS1.yaml | yaml-get --query=/aliases -
["This is a reusable String value", 5280, "A DIFFERENT STRING VALUE", 5280]

In most cases, this is probably the preferred outcome.

Hash Anchors

Hash Anchors are quite a bit more complex than Scalar Anchors. In turn, they are extremely useful at reducing duplication of Hash structure and simultaneously reusing more than one key-value pair. Rather than create a single data element (a Scalar value) which can be reused throughout the remainder of the YAML document, a Hash Anchor enables repeatedly reusing an entire Hash. Any number of the key-value pairs within the Anchored Hash can be discretely overridden at each point of reuse, allowing "defaults" within the Anchored Hash to be set to concrete values. Further, multiple Anchored Hashes can be combined to produce novel combinations of reusable Hash fragments.

A simple example might be a short set of publications, like:

File: LHS2a.yaml

book_defaults: &defaults
  author: UNKNOWN
  publisher: UNKNOWN
  publication_year: UNKNOWN

publications:
  books:
    'A Novel':
      <<: *defaults
      author: John Doe
      publisher: Books-R-Us
    'A Tech Manual':
      <<: *defaults
      publication_year: 1998
      contributing_authors:
        - Jane Doe
        - Billy Bob Joe Frank

Note that Hash Anchor names come after the name of the Hash being Anchored and the name of the Anchor does not need to match the name of the key defining the reusable Hash; this is the reverse of Scalar Anchors. Notice also the YAML Merge Key, <<:, later in the document. When present in YAML files, the YAML Merge Key is an instruction to embed only those keys (and their values) from the source Anchored Hash which are not locally defined for the target Hash (only copy keys not already defined). This is all separate from the capabilities provided by the yaml-merge tool; this very powerful capability is just native YAML.

To explore this concept, consider these queries and their results:

yaml-get --query='/&defaults' LHS2.yaml
{"author": "UNKNOWN", "publisher": "UNKNOWN", "publication_year": "UNKNOWN"}

yaml-get --query="/publications/books/'A Novel'" LHS2.yaml
{"author": "John Doe", "publisher": "Books-R-Us", "publication_year": "UNKNOWN"}

yaml-get --query="/publications/books/'A Tech Manual'" LHS2.yaml
{"publication_year": 1998, "contributing_authors": ["Jane Doe", "Billy Bob Joe Frank"], "author": "UNKNOWN", "publisher": "UNKNOWN"}

You can see that each book record always has all of the fields provided by the &defaults Anchored Hash, even when the data for the book is not specified. Further, novel fields in a book record extend the definition of the record, beyond the fields provided by the default.

Note that it is convention to place the YAML Merge Key as the first child of a Hash being internally merged. However, the operator could be at any child position within the Hash. The specification (draft) for this operator specifically stipulates that a YAML Merge Key will never cause any existing keys already defined within the target Hash to be overwritten. This holds true even when merging multiple Anchored Hashes into the same Hash; only the first instance of any given unused key from the Anchored Hash list (processed left-to-right, top-to-bottom) is merged in, and any locally-defined keys always override same-named keys from the Anchored Hashes.

Hash Anchors get even more delightfully complex than this, enabling further specialization and reuse of Hash fragments. Let's say that book and magazine publications share some attributes, but not all. Further, let's assume our data provider keeps book data apart from magazine data in some back-end storage solution. Should we need to merge such data together for further aggregation or analysis, we could encounter an Anchor merge conflict.

Take these two YAML files for example:

File: LHS2b.yaml

publication_defaults: &pubdefs
  publisher: UNKNOWN
  publication_year: UNKNOWN

book_defaults: &defaults
  author: UNKNOWN

publications:
  books:
    'A Novel':
      <<:
        - *pubdefs
        - *defaults
      author: John Doe
      publisher: Books-R-Us
    'A Tech Manual':
      <<: [*pubdefs, *defaults]
      publication_year: 1998
      contributing_authors:
        - Jane Doe
        - Billy Bob Joe Frank

File: RHS2.yaml

publication_defaults: &pubdefs
  publisher: UNKNOWN
  publication_year: UNKNOWN

magazine_defaults: &defaults
  glossy: false
  serial_number: UNKNOWN

publications:
  magazines:
    'Video Games Today':
      <<: [*pubdefs, *defaults]
      glossy: true
      publication_year: 1994
      serial_number: 7
    'Bigger Trucks':
      <<: [*pubdefs, *defaults]
      publication_year: 2020

We are now composing our records by using Anchored Hash fragments. In our fictional case, each record uses both fragments but this needn't always be the case. Purely for demonstration, LHS2b.yaml presents the YAML Merge Key's arguments (both Aliases) in two styles: block and flow. By convention, flow style is normally used but the two forms are equivalent. The yaml-merge tool uses the flow style when writing out its results.

Excepting that the &defaults Anchored Hash is now a fragment, performing the same queries as before against LHS2b.yaml yields the same answers:

yaml-get --query='/&pubdefs' LHS2b.yaml
{"publisher": "UNKNOWN", "publication_year": "UNKNOWN"}

yaml-get --query='/&defaults' LHS2b.yaml
{"author": "UNKNOWN"}

yaml-get --query="/publications/books/'A Novel'" LHS2b.yaml
{"author": "John Doe", "publisher": "Books-R-Us", "publication_year": "UNKNOWN"}

yaml-get --query="/publications/books/'A Tech Manual'" LHS2b.yaml
{"publication_year": 1998, "contributing_authors": ["Jane Doe", "Billy Bob Joe Frank"], "publisher": "UNKNOWN", "author": "UNKNOWN"}

For contrast with later examples, here are some queries against RHS2.yaml:

yaml-get --query='/&pubdefs' RHS2.yaml
{"publisher": "UNKNOWN", "publication_year": "UNKNOWN"}

yaml-get --query='/&defaults' RHS2.yaml
{"glossy": false, "serial_number": "UNKNOWN"}

yaml-get --query="/publications/magazines/'Video Games Today'" RHS2.yaml
{"glossy": true, "publication_year": 1994, "serial_number": 7, "publisher": "UNKNOWN"}

yaml-get --query="/publications/magazines/'Bigger Trucks'" RHS2.yaml
{"publication_year": 2020, "publisher": "UNKNOWN", "glossy": false, "serial_number": "UNKNOWN"}

Can you see where an Anchor merge conflict will occur when we attempt to merge RHS2.yaml into LHS2b.yaml? Answer: the &defaults Anchor name is being used on two different Hashes between LHS2b.yaml and RHS2.yaml; this is the conflict. The &pubdefs Anchor is non-conflicting because the Hash defined in both documents is identical.

Let's take a look at the various means by which the yaml-merge tool can deal with this conflict. Some are more useful than others.

Left Hash Anchor Override

When you are absolutely certain that all Hash Anchor definitions in the LHS document are absolute and mustn't be overridden by any RHS re-definitions, use --anchors=left or -a left. Doing so in the example case produces this document:

---
publication_defaults: &pubdefs
  publisher: UNKNOWN
  publication_year: UNKNOWN
book_defaults: &defaults
  author: UNKNOWN
magazine_defaults: *defaults
publications:
  books:
    'A Novel':
      <<: [*pubdefs, *defaults]
      author: John Doe
      publisher: Books-R-Us
    'A Tech Manual':
      <<: [*pubdefs, *defaults]
      publication_year: 1998
      contributing_authors:
        - Jane Doe
        - Billy Bob Joe Frank
  magazines:
    'Video Games Today':
      <<: [*pubdefs, *defaults]
      glossy: true
      publication_year: 1994
      serial_number: 7
    'Bigger Trucks':
      <<: [*pubdefs, *defaults]
      publication_year: 2020

You can see that the conflicting definition of &defaults from the RHS document was overwritten by the LHS definition. This resulted in some expected data loss; the keys unique to magazine_defaults were destroyed to make magazine_defaults a copy of publication_defaults. For our case, this isn't particularly helpful but it is exactly what we instructed yaml-merge to do.

If we re-run every query against the merged result, we see some interesting -- albeit unhelpful -- changes:

yaml-merge --anchors=left LHS2b.yaml RHS2.yaml | yaml-get --query='/&pubdefs' -
{"publisher": "UNKNOWN", "publication_year": "UNKNOWN"}

yaml-merge --anchors=left LHS2b.yaml RHS2.yaml | yaml-get --query='/&defaults' -
{"author": "UNKNOWN"}
{"author": "UNKNOWN"}

yaml-merge --anchors=left LHS2b.yaml RHS2.yaml | yaml-get --query="/publications/books/'A Novel'" -
{"author": "John Doe", "publisher": "Books-R-Us", "publication_year": "UNKNOWN"}

yaml-merge --anchors=left LHS2b.yaml RHS2.yaml | yaml-get --query="/publications/books/'A Tech Manual'" -
{"publication_year": 1998, "contributing_authors": ["Jane Doe", "Billy Bob Joe Frank"], "publisher": "UNKNOWN", "author": "UNKNOWN"}

yaml-merge --anchors=left LHS2b.yaml RHS2.yaml | yaml-get --query="/publications/magazines/'Video Games Today'" -
{"glossy": true, "publication_year": 1994, "serial_number": 7, "publisher": "UNKNOWN", "author": "UNKNOWN"}

yaml-merge --anchors=left LHS2b.yaml RHS2.yaml | yaml-get --query="/publications/magazines/'Bigger Trucks'" -
{"publication_year": 2020, "publisher": "UNKNOWN", "author": "UNKNOWN"}

Of note:

  1. --query='/&defaults' now returns two matches rather than just one. This is because magazine_defaults is both a complete duplicate of book_defaults and still a separate Hash in the root of the document.
  2. --query="/publications/magazines/'Video Games Today'" now has an author attribute, injected from the re-defined &defaults Anchored Hash.
  3. --query="/publications/magazines/'Bigger Trucks'" now has an author attribute (same reason as above) and lost its glossy attribute (because we destroyed it by forcing the left Anchor definition to overwrite the RHS definition.
  4. All other answers are identical.

Right Hash Anchor Override

When you are absolutely certain that all Hash Anchor re-definitions in the RHS document are absolute and must overwrite any conflicting LHS definitions, use --anchors=right or -a right. Doing so in the example case produces this document:

---
publication_defaults: &pubdefs
  publisher: UNKNOWN
  publication_year: UNKNOWN
book_defaults: &defaults
  glossy: false
  serial_number: UNKNOWN
magazine_defaults: *defaults
publications:
  books:
    'A Novel':
      <<: [*pubdefs, *defaults]
      author: John Doe
      publisher: Books-R-Us
    'A Tech Manual':
      <<: [*pubdefs, *defaults]
      publication_year: 1998
      contributing_authors:
        - Jane Doe
        - Billy Bob Joe Frank
  magazines:
    'Video Games Today':
      <<: [*pubdefs, *defaults]
      glossy: true
      publication_year: 1994
      serial_number: 7
    'Bigger Trucks':
      <<: [*pubdefs, *defaults]
      publication_year: 2020

You can see that the conflicting definition of &defaults from the RHS document overwrote the original LHS definition. The book_defaults Hash was overwritten with the structure and content of magazine_defaults from the RHS document. This resulted in some expected data loss; the keys unique to book_defaults were destroyed to make it a full copy of magazine_defaults. As with Left Hash Anchor Override, this isn't particularly helpful but it is exactly what we instructed yaml-merge to do.

If we re-run every query against the merged result, we see some interesting -- arguably unhelpful -- changes:

yaml-merge --anchors=right LHS2b.yaml RHS2.yaml | yaml-get --query='/&pubdefs' -
{"publisher": "UNKNOWN", "publication_year": "UNKNOWN"}

yaml-merge --anchors=right LHS2b.yaml RHS2.yaml | yaml-get --query='/&defaults' -
{"glossy": false, "serial_number": "UNKNOWN"}
{"glossy": false, "serial_number": "UNKNOWN"}

yaml-merge --anchors=right LHS2b.yaml RHS2.yaml | yaml-get --query="/publications/books/'A Novel'" -
{"author": "John Doe", "publisher": "Books-R-Us", "publication_year": "UNKNOWN", "glossy": false, "serial_number": "UNKNOWN"}

yaml-merge --anchors=right LHS2b.yaml RHS2.yaml | yaml-get --query="/publications/books/'A Tech Manual'" -
{"publication_year": 1998, "contributing_authors": ["Jane Doe", "Billy Bob Joe Frank"], "publisher": "UNKNOWN", "glossy": false, "serial_number": "UNKNOWN"}

yaml-merge --anchors=right LHS2b.yaml RHS2.yaml | yaml-get --query="/publications/magazines/'Video Games Today'" -
{"glossy": true, "publication_year": 1994, "serial_number": 7, "publisher": "UNKNOWN"}

yaml-merge --anchors=right LHS2b.yaml RHS2.yaml | yaml-get --query="/publications/magazines/'Bigger Trucks'" -
{"publication_year": 2020, "publisher": "UNKNOWN", "glossy": false, "serial_number": "UNKNOWN"}

Of note:

  1. --query='/&defaults' again returns two matches rather than just one. This is because magazine_defaults is both a complete duplicate of the redefined book_defaults Hash and still a separate Hash in the root of the document.
  2. --query="/publications/books/'A Novel'" now has glossy and serial_number attributes.
  3. --query="/publications/books/'A Tech Manual'" also now has both glossy and serial_number attributes but lost its author attribute.
  4. All other answers are identical.

Rename Conflicting Hash Anchors

In most -- but certainly not all -- cases, this is the best Anchor conflict resolution option. It wholly preserves every Anchored Hash and their Aliases, fully preserving the crucial data from all merged documents. When setting --anchors=rename or -a rename, a more useful document is generated for this example use-case:

---
publication_defaults: &pubdefs
  publisher: UNKNOWN
  publication_year: UNKNOWN
book_defaults: &defaults
  author: UNKNOWN
magazine_defaults: &defaults_1
  glossy: false
  serial_number: UNKNOWN
publications:
  books:
    'A Novel':
      <<: [*pubdefs, *defaults]
      author: John Doe
      publisher: Books-R-Us
    'A Tech Manual':
      <<: [*pubdefs, *defaults]
      publication_year: 1998
      contributing_authors:
        - Jane Doe
        - Billy Bob Joe Frank
  magazines:
    'Video Games Today':
      <<: [*pubdefs, *defaults_1]
      glossy: true
      publication_year: 1994
      serial_number: 7
    'Bigger Trucks':
      <<: [*pubdefs, *defaults_1]
      publication_year: 2020

The Anchor conflict was resolved by renaming the conflicting Anchor from the RHS document to &defaults_1. At this point, no data was lost and the original queries return the same results from the two original documents excepting that we must use the new Anchor name to find the new definition of magazine_defaults by its Anchor name. [NOTE: We could just search for /magazine_defaults to find it but if we had to search by its Anchor name, it will have changed in the merged document.] The original queries against the merged document now return the original data:

yaml-merge --anchors=rename LHS2b.yaml RHS2.yaml | yaml-get --query='/&pubdefs' -
{"publisher": "UNKNOWN", "publication_year": "UNKNOWN"}

yaml-merge --anchors=rename LHS2b.yaml RHS2.yaml | yaml-get --query='/&defaults' -
{"author": "UNKNOWN"}

yaml-merge --anchors=rename LHS2b.yaml RHS2.yaml | yaml-get --query='/&defaults_1' -
{"glossy": false, "serial_number": "UNKNOWN"}

yaml-merge --anchors=rename LHS2b.yaml RHS2.yaml | yaml-get --query="/publications/books/'A Novel'" -
{"author": "John Doe", "publisher": "Books-R-Us", "publication_year": "UNKNOWN"}

yaml-merge --anchors=rename LHS2b.yaml RHS2.yaml | yaml-get --query="/publications/books/'A Tech Manual'" -
{"publication_year": 1998, "contributing_authors": ["Jane Doe", "Billy Bob Joe Frank"], "publisher": "UNKNOWN", "author": "UNKNOWN"}

yaml-merge --anchors=rename LHS2b.yaml RHS2.yaml | yaml-get --query="/publications/magazines/'Video Games Today'" -
{"glossy": true, "publication_year": 1994, "serial_number": 7, "publisher": "UNKNOWN"}

yaml-merge --anchors=rename LHS2b.yaml RHS2.yaml | yaml-get --query="/publications/magazines/'Bigger Trucks'" -
{"publication_year": 2020, "publisher": "UNKNOWN", "glossy": false, "serial_number": "UNKNOWN"}

With a now-complete data-set, we could run some more interesting queries, like:

# Identify all KNOWN Publication Years in ALL of the publications:
yaml-merge --anchors=rename LHS2b.yaml RHS2.yaml | yaml-get --query="/publications/[.!='']/[.!='']/[publication_year!=UNKNOWN]" -
1998
1994
2020

Configuration File Options

While the yaml-merge tool can read per YAML Path merging options from an INI-Style configuration file via its --config (-c) argument, this is not supported for Anchor conflict resolutions. You can however, set a default resolution in the [defaults] section.

Configuration File Section: defaults

The [defaults] section permits a key named, anchors, which behaves identically to the --anchors (-a) command-line argument to the yaml-merge tool. The [defaults]anchors setting is overridden by the same-named command-line argument, when supplied. In practice, this file may look like:

File merge-options.ini

[defaults]
anchors = rename

Note the spaces around the = sign are optional but only an = sign may be used to separate each key from its value.

Configuration File Section: rules

At this time, Anchors are handled only in the document-wide scope. The [rules] section does not support specifying per YAML Path Anchor resolution options.

Clone this wiki locally