有没有一种方法可以替代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_id
,并在由*some_id
(而不是节点)指定节点和别名节点之前插入。
这与在字符串级别进行替换不同,因为在解析YAML文件期间可以保留引用。就像在Python中为集合类型上的所有锚点加载YAML一样(即在标量上使用锚点时不这样):
import sys
import ruamel.yaml as yaml
yaml_str = """\
sub: &sub0 [a, b, 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
"""
data1 = yaml.load(yaml_str, Loader=yaml.RoundTripLoader)
# the loaded elements point to the same list
assert data1['sub'] is data1['command']['params']['cmd1']['enum']
# change in cmd2
data1['command']['params']['cmd2']['enum'][3] = 'X'
yaml.dump(data1, sys.stdout, Dumper=yaml.RoundTripDumper, indent=4)
这将输出:
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
请注意,原始锚点名称保留在ruamel.yaml中。
如果您不希望在输出中使用锚点和别名,则可以重写的子类中的ignore_aliases
方法(该方法带有两个参数,但使用时不必知道这一点):RoundTripRepresenter
RoundTripDumper
lambda *args: ....
dumper = yaml.RoundTripDumper
dumper.ignore_aliases = lambda *args : True
yaml.dump(data1, sys.stdout, Dumper=dumper, indent=4)
这使:
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更新中实现
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句