How can I do string concatenation, or string replacement in YAML?

ConcatenationYaml

Concatenation Problem Overview


I have this:

user_dir: /home/user
user_pics: /home/user/pics

How could I use the user_dir for user_pics? If I have to specify other properties like this, it would not be very DRY.

Concatenation Solutions


Solution 1 - Concatenation

You can use a repeated node, like this:

user_dir: &user_home /home/user
user_pics: *user_home

I don't think you can concatenate though, so this wouldn't work:

user_dir: &user_home /home/user
user_pics: *user_home/pics

Solution 2 - Concatenation

It's surprising, since the purpose of YAML anchors & references is to factor duplication out of YAML data files, that there isn't a built-in way to concatenate strings using references. Your use case of building up a path name from parts is a good example -- there must be many such uses.

Fortunately there's a simple way to add string concatenation to YAML via custom tags in Python.

import yaml

## define custom tag handler
def join(loader, node):
    seq = loader.construct_sequence(node)
    return ''.join([str(i) for i in seq])

## register the tag handler
yaml.add_constructor('!join', join)

## using your sample data
yaml.load("""
user_dir: &DIR /home/user
user_pics: !join [*DIR, /pics]
""")

Which results in:

{'user_dir': '/home/user', 'user_pics': '/home/user/pics'}

You can add more items to the array, like " " or "-", if the strings should be delimited.

Solution 3 - Concatenation

If you are using python with PyYaml, joining strings is possible within the YAML file. Unfortunately this is only a python solution, not a universal one:

with os.path.join:

user_dir: &home /home/user
user_pics: !!python/object/apply:os.path.join [*home, pics]

with string.join (for completeness sake - this method has the flexibility to be used for multiple forms of string joining:

user_dir: &home /home/user
user_pics: !!python/object/apply:string.join [[*home, pics], /]

Solution 4 - Concatenation

I would use an array, then join the string together with the current OS Separator Symbol

like this:

default: &default_path "you should not use paths in config"
pictures:
  - *default_path
  - pics

Solution 5 - Concatenation

Seems to me that YAML itself does not define way to do this.

Good news are that YAML consumer might be able to understand variables.
What will use Your YAML?

Solution 6 - Concatenation

string.join() won't work in Python3, but you can define a !join like this:

import functools
import yaml

class StringConcatinator(yaml.YAMLObject):
    yaml_loader = yaml.SafeLoader
    yaml_tag = '!join'
    @classmethod
    def from_yaml(cls, loader, node):
        return functools.reduce(lambda a, b: a.value + b.value, node.value)

c=yaml.safe_load('''
user_dir: &user_dir /home/user
user_pics: !join [*user_dir, /pics]''')
print(c)

Solution 7 - Concatenation

As of August 2019:

To make Chris' solution work, you actually need to add Loader=yaml.Loader to yaml.load(). Eventually, the code would look like this:

import yaml

## define custom tag handler
def join(loader, node):
    seq = loader.construct_sequence(node)
    return ''.join([str(i) for i in seq])

## register the tag handler
yaml.add_constructor('!join', join)

## using your sample data
yaml.load("""
user_dir: &DIR /home/user
user_pics: !join [*DIR, /pics]
""", Loader=yaml.Loader)

See this GitHub issue for further discussion.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGeoView Question on Stackoverflow
Solution 1 - ConcatenationBrian WellsView Answer on Stackoverflow
Solution 2 - ConcatenationChris JohnsonView Answer on Stackoverflow
Solution 3 - Concatenationuser2502636View Answer on Stackoverflow
Solution 4 - ConcatenationAdamView Answer on Stackoverflow
Solution 5 - ConcatenationArnis LapsaView Answer on Stackoverflow
Solution 6 - ConcatenationbryanView Answer on Stackoverflow
Solution 7 - ConcatenationbmiselisView Answer on Stackoverflow