使用 Python 替换 YAML 中的字符串



我有以下 YAML:

instance:
name: test
flavor: x-large
image: centos7
tasks:
centos-7-prepare:
priority: 1
details::
ha: 0
args:
template: &startup
name: startup-centos-7
version: 1.2
timeout: 1800
centos-7-crawl:
priority: 5
details::
ha: 1
args:
template: *startup
timeout: 0

第一个任务定义模板名称和版本,然后由其他任务使用。模板定义不应更改,但其他定义(尤其是任务名称(将更改。

在 Python 中更改模板名称和版本的最佳方法是什么?

我有以下用于匹配的正则表达式(使用 re。多特尔(:

template:.*name: (.*?)version: (.*?)s

但是到目前为止还没有弄清楚 re.sub 的用法。或者有没有更方便的方法?

对于 YAML 的这种往返(加载-修改-转储(,您应该使用ruamel.yaml(免责声明:我是该包的作者(。

如果您的输入是input.yaml,则可以相对容易地找到nameversion在密钥下template并更新它们:

import sys
import ruamel.yaml
def find_template(d):
if isinstance(d, list):
for elem in d:
x = find_template(elem)
if x is not None:
return x
elif isinstance(d, dict):
for k in d:
v = d[k]
if k == 'template':
if 'name' in v and 'version' in v:
return v
x = find_template(v)
if x is not None:
return x
return None

yaml = ruamel.yaml.YAML()
# yaml.indent(mapping=4, sequence=4, offset=2)
yaml.preserve_quotes = True
with open('input.yaml') as ifp:
data = yaml.load(ifp)
template = find_template(data)
template['name'] = 'startup-centos-8'
template['version'] = '1.3'
yaml.dump(data, sys.stdout)

这给了:

instance:
name: test
flavor: x-large
image: centos7
tasks:
centos-7-prepare:
priority: 1
'details:':
ha: 0
args:
template: &startup
name: startup-centos-8
version: '1.3'
timeout: 1800
centos-7-crawl:
priority: 5
'details:':
ha: 1
args:
template: *startup
timeout: 0

请注意,我在输入中插入的(多余的(引号以及注释和别名的名称将被保留。

我会将yaml文件解析为字典,然后编辑字段并将字典写回yaml。

请参阅此问题以讨论在python中解析yaml如何解析Python中的YAML文件,但我认为您最终会得到这样的东西。

from ruamel.yaml import YAML
from io import StringIO
yaml=YAML(typ='safe')
yaml.default_flow_style = False
#Parse from string
myConfig = yaml.load(doc)
#Example replacement code
for task in myConfig["tasks"]:
if myConfig["tasks"][task]["details"]["args"]["template"]["name"] == "&startup":
myConfig["tasks"][task]["details"]["args"]["template"]["name"] = "new value"
#Convert back to string
buf = StringIO()
yaml.dump(myConfig, buf)
updatedYml = buf.getvalue()

最新更新