是否可以在YAML中进行字符串替换?

是否可以在YAML中进行字符串替换?,yaml,Yaml,有没有办法在YAML中替换字符串。例如,我想定义一次sub,并在整个YAML文件中使用它 sub: ['a', 'b', 'c'] command: params: cmd1: type: string enum : # Get the list defined in 'sub' description: Exclude commands from the test list. c

有没有办法在YAML中替换字符串。例如,我想定义一次
sub
,并在整个YAML文件中使用它

sub: ['a', 'b', 'c']
command:
    params:
        cmd1:
            type: string
            enum :   # Get the list defined in 'sub'
            description: Exclude commands from the test list.
        cmd2:
            type: string
            enum:   # Get the list defined in 'sub'

在YAML中不能真正替换字符串值,例如用另一个子字符串“”替换某个字符串的子字符串。然而,YAML确实有可能将一个节点(在您的例子中是列表['a'、'b'、'c'])标记为一个,并将其重新用作一个

锚定采用
&some\u id
的形式,并在
*some\u id
指定节点和别名节点(而不是节点)之前插入

这与字符串级别上的替换不同,因为在解析YAML文件期间,可以保留引用。在Python中为集合类型上的任何锚加载YAML时,情况就是这样(即,在标量上使用锚时,not):

这将输出:

sub: &sub0 [a, X, c]
command:
    params:
        cmd1:
            type: string
            # Get the list defined in 'sub'
            enum: *sub0
            description: Exclude commands from the test list.
        cmd2:
            type: string
            # Get the list defined in 'sub'
            enum: *sub0
请注意,原始锚点名称保留在中

如果您不想在输出中使用锚点和别名,可以在
RoundTripDumper
RoundTripRepresenter
子类中重写
ignore_alias
方法(该方法需要两个参数,但使用
lambda*args:..
您不必知道):

其中:

sub: [a, X, c]
command:
    params:
        cmd1:
            type: string
            # Get the list defined in 'sub'
            enum: [a, X, c]
            description: Exclude commands from the test list.
        cmd2:
            type: string
            # Get the list defined in 'sub'
            enum: [a, X, c]
这个技巧可以用来读取YAML文件,就像你做了字符串替换一样,通过重新读取你转储的材料而忽略别名:

data2 = yaml.load(yaml.dump(yaml.load(yaml_str, Loader=yaml.RoundTripLoader),
                    Dumper=dumper, indent=4), Loader=yaml.RoundTripLoader)

# these are lists with the same value
assert data2['sub'] == data2['command']['params']['cmd1']['enum']
# but the loaded elements do not point to the same list
assert data2['sub'] is not data2['command']['params']['cmd1']['enum']

data2['command']['params']['cmd2']['enum'][5] = 'X'

yaml.dump(data2, sys.stdout, Dumper=yaml.RoundTripDumper, indent=4)
现在只有一个
'b'
变成了
'X'

sub: [a, b, c]
command:
    params:
        cmd1:
            type: string
            # Get the list defined in 'sub'
            enum: [a, b, c]
            description: Exclude commands from the test list.
        cmd2:
            type: string
            # Get the list defined in 'sub'
            enum: [a, X, c]
如上所述,仅当在集合类型上使用锚定/别名时,而不是在标量上使用锚定/别名时,才需要这样做


由于YAML可以创建对象,因此有可能影响 如果创建了这些对象,则将使用解析器。描述如何执行此操作。

²保留名称最初不可用,但在ruamel.yaml的更新中实现。请看:我更改了您的yaml代码,因为它在
b
之后的序列
sub
中遗漏了一个引号。请注意,这些引号是多余的,我在回答中使用您的输入时遗漏了它们。另请参阅:
data2 = yaml.load(yaml.dump(yaml.load(yaml_str, Loader=yaml.RoundTripLoader),
                    Dumper=dumper, indent=4), Loader=yaml.RoundTripLoader)

# these are lists with the same value
assert data2['sub'] == data2['command']['params']['cmd1']['enum']
# but the loaded elements do not point to the same list
assert data2['sub'] is not data2['command']['params']['cmd1']['enum']

data2['command']['params']['cmd2']['enum'][5] = 'X'

yaml.dump(data2, sys.stdout, Dumper=yaml.RoundTripDumper, indent=4)
sub: [a, b, c]
command:
    params:
        cmd1:
            type: string
            # Get the list defined in 'sub'
            enum: [a, b, c]
            description: Exclude commands from the test list.
        cmd2:
            type: string
            # Get the list defined in 'sub'
            enum: [a, X, c]