首页 > 解决方案 > 使用嵌入式 JSON 加载 YAML 时格式不正确(无换行符)

问题描述

我正在尝试解析文件中的 YAML 输入:

root: {
   children : { key: "test-key", version: "{{ test_version | default( '1.0.0-SNAPSHOT' ) }}"}
}

我正在使用 ruamel.yaml,使加载的代码部分配置为保留引号,然后我手动添加一个新条目:

yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
yaml.width = 4096
yaml.indent(sequence=4, offset=2)

with open(yml_file, 'r') as file:
   print("Modifying file: '%s'..." % str(file))
   data = yaml.load(file)

data['root'][new_project_name.lower()] = {'key': "%s" % new_project_name.lower(),
                                                          'test_version': "{{ %s_version | default(\'1.0.0-SNAPSHOT\') }}"
                                                                     % new_project_name.lower()}

 with open(yml_file, 'w') as file:
       yaml.dump(data, file)

问题是,当使用新条目写入文件时,我将所有内容都放在同一行中,因此似乎没有保留新行(CR LF),(它似乎甚至在没有它们的情况下加载它)你知道有没有办法保存它们?

输出是(同一行中的所有内容):

root: {children : { key: "test-key", version: "{{ test_version | default( '1.0.0-SNAPSHOT' ) }}"}}

标签: python-3.xruamel.yaml

解决方案


ruamel.yaml不保留注释,也不保留flow style中的间距。如果您关心布局,以便您的 YAML 更易于人类阅读,那么您应该尽可能对叶节点使用流样式。这是使用时的默认转储样式YAML(typ='fast')

当您像输入一样嵌套流样式时,这些节点上的流样式将被保留,并完成标准格式设置(如果行变大,则换行除外,所有内容都在一行上)。

设置缩进级别仅影响块样式结构。

您应该将输入更改为仅叶节点流样式,以获得更好的可读性:

root: 
   children: {key: "test-key", version: "{{ test_version | default( '1.0.0-SNAPSHOT' ) }}"}

这将加载到与您的输入相同的数据结构。

有了它,您现在可以执行以下操作:

import sys
import ruamel.yaml

yml_file = 'input.yaml'
new_project_name = 'NPN'


yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
yaml.width = 4096

with open(yml_file, 'r') as file:
   print("Modifying file: '%s'..." % str(file))
   data = yaml.load(file)

npn_lower = new_project_name.lower()

data['root'][npn_lower] = m = ruamel.yaml.comments.CommentedMap([
    ('key',  "%s" % npn_lower),
    ('test_version', "{{ %s_version | default(\'1.0.0-SNAPSHOT\') }}" % npn_lower)
])
m.fa.set_flow_style()

with open('output.yaml', 'w') as fp:
    yaml.dump(data, fp)

打印:

Modifying file: '<_io.TextIOWrapper name='input.yaml' mode='r' encoding='UTF-8'>'...

并具有output.yaml

root:
  children: {key: "test-key", version: "{{ test_version | default( '1.0.0-SNAPSHOT' ) }}"}
  npn: {key: npn, test_version: "{{ npn_version | default('1.0.0-SNAPSHOT') }}"}

注意事项:

  • 添加一个 CommentedMap,因为在普通 dict 上您不能单独设置流样式,并且您需要这样做,因为这不再是嵌套的流样式。元素作为元组列表添加,与旧版本的 Python 一样,键顺序不能保证与输入中的相同。您还可以创建一个空CommentedMap()并一次添加一个键/值对。

  • 在尝试过程中(以及此处提供的代码),更改输入文件始终是一个坏主意,因为对于每次测试运行,您的输入都必须还原。


推荐阅读