Compositing multiple YAML sources
May 15, 2025 ยท View on GitHub
Contents:
Compositing
config_utilities includes a command line tool that will take multiple sources of YAML and dump the combined (composited) YAML to stdout. This is designed for the use-case where a base YAML file contains the majority of a configuration, and small overlays are used to adapt or fill in the configuration for different variants of a system.
You can run composite-configs -h for more information on the utility.
How compositing works
This tutorial explains how different sources of YAML data are combined into a single YAML tree, and is primarily a more in-depth explanation of the behavior of the command line based YAML parser. Functionally, the command line parser is doing the following after parsing the various command line options.
std::vector<YAML::Node> inputs; // parsed YAML from either files or raw YAML strings
YAML::Node combined; // result YAML node
for (const auto& input : inputs) {
internal::mergeYamlNodes(combined, input, MergeMode::APPEND);
}
Controlling compositing behavior
The default ROS-like merging behavior (append) can be overridden by inline tags. The following behaviors are currently available:
!append: Matched sequences are appended together (specifically, the right sequence is appended to the left)!replace: Matched keys result in the right key overriding the left!merge: Matched keys (including sequence indices) are recursed into. Any unmatched keys are added
These merging behaviors apply to all children below the tag (until another tag is present).
Example behavior:
# original YAML (left)
root: {child: {a: 42, c: 0}, numbers: [1, 2, 3], scalar: -1}
# new YAML to merge (right)
root: !TAG {child: {a: 12, b: 13}, numbers: [4, 5], other: temp}
# result of merging right into left with !append in place of !TAG
root: {child: {a: 12, c: 0, b: 13}, numbers: [1, 2, 3, 4, 5], scalar: -1, other: temp}
# result of merging right into left with !replace in place of !TAG
root: {child: {a: 12, b: 13}, numbers: [4, 5], scalar: -1, other: temp}
# result of merging right into left with !merge in place of !TAG
root: {child: {a: 12, c: 0, b: 13}, numbers: [4, 5, 3], scalar: -1, other: temp}
Substitutions
We also support a substitution language for interpolating values into YAML data. These (closely) resemble the ROS substitution language. Substitutions are performed with respect to a context that may have some variables that can be used.
As an example, resolving substitutions in the following YAML (with the context num_prints = 5)
input_filepath: $<env HOME>/some/random/file
num_prints: $<var num_prints>
would result in
input_filepath: /home/user/some/random/file
num_prints: 5
after calling resolveSubstitutions on the parsed YAML.