如何读取 YAML 文件中的组件,以便我可以使用 ruamel.yaml 编辑它的键值? [英] How to read a component in YAML file so that I can edit it's key value using ruamel.yaml?

查看:23
本文介绍了如何读取 YAML 文件中的组件,以便我可以使用 ruamel.yaml 编辑它的键值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的 YAML 文件(input.yaml):

This is my YAML file (input.yaml):

team_member:
  name: Max
  hobbies:
    - Reading

team_leader:
  name: Stuart
  hobbies:
    - dancing

我想编辑此 YAML 文件以在关键爱好"中添加更多值,例如:

I want to edit this YAML file to add more values in key 'hobbies', example:

team_member:
  name: Max
  hobbies:
    - Reading
    - Painting

team_leader:
  name: Stuart
  hobbies:
    - Dancing
    - Fishing

我尝试实现代码 Anthon 以适应我的情况,但它根本没有帮助,因为缩进级别该 YAML 文件与我的不同.
示例:

I tried to implement the code Anthon to fit my situation but it didn't helped at all, because the indention level of that YAML file is different from mine.
Example:

import sys
import ruamel.yaml

yaml = ruamel.yaml.YAML()
# yaml.preserve_quotes = True
with open('input.yaml') as fp:
    data = yaml.load(fp)
for elem in data:
    if elem['name'] == 'Stuart':
         elem['hobbies'] = ['Fishing']
         break  # no need to iterate further
yaml.dump(data, sys.stdout)

我收到错误TypeError('string indices must be integers',)",我知道这段代码可能完全错误,但我是 ruamel.yaml 的新手.

I get error "TypeError('string indices must be integers',)", I know this code might be completely wrong, but I am new to ruamel.yaml.

如何编码?

推荐答案

显示的错误消息中缺少的是行号(我假设它是 9).那指向那条线

The thing missing form the error message displayed is the line number (I assume that it is 9). That points to the line

    if elem['name'] == 'Stuart':

如果这不能给你一个线索,我在这种情况下推荐的方法是开始添加一些 print 函数,这样你就知道你在做什么.for 循环如下所示:

And if that doesn't give you a clue, the approach that I recommend in such cases is starting to add some print functions, so that you know what you are working on. The for loop looks like:

for elem in data:
    print('elem', elem)
    if elem['name'] == 'Stuart':
         print('elem->hobbies', elem['hobbies'])
         elem['hobbies'] = ['Fishing']

打印出来

 elem team_member

在抛出异常之前,我希望这会让你意识到你不是在迭代列表的 elements(项目),而是在 keys 的 dict(从 YAML 中的根级别映射构造).而与键关联的是具有键name和键hobbies的对象.

before the exception is thrown, and I hope that will make you realize your are not iterating over the elements (items) of a list, but over the keys of a dict (constructed from the root level mapping in your YAML). And the value associated with the key is the object having a key name and a key hobbies.

因此,将变量 elem 更改为 key 以明确您正在处理的内容,然后继续使用 value,关联的值在该循环中使用该键而不是 elem ¹:

So change the variable elem to key to make clear what you're handling and then proceed to work with value, the value associated with that key instead of elem within that loop¹:

for key in data:
    value = data[key]
    if value['name'] == 'Stuart':
         print('value->hobbies', value['hobbies'])
         value['hobbies'] = ['Fishing']

这给出了:

value->hobbies ['dancing']
team_member:
  name: Max
  hobbies:
  - Reading

team_leader:
  name: Stuart
  hobbies:
  - Fishing

所以我们摆脱了异常,但结果并不完全是您想要的.键爱好"的元素 dancing 消失了,因为您为该键分配了一个新的(列表)值,而您应该做的是将单个项目附加到列表中.我们现在也可以去掉打印功能了:

So we got rid of the exception, but the result is not exactly what you want. The element dancing for the key 'hobbies' is gone, because you assign a new (list) value to that key, whereas what you should do is append a single item to the list. We can also get rid of the print function by now:

for key in data:
    value = data[key]
    if value['name'] == 'Stuart':
         value['hobbies'].append('Fishing')

这将在文件的最终序列中为您提供两个项目.还有一些问题需要解决:

This will get you two items in the final sequence in the file. There is a few more things to address:

  • dancing 的大写不正确.要纠正这个问题,如果只有一个元素,请添加一行处理列表
  • 需要添加名称 Max 的代码(这就是为什么您需要去掉代码中的 break)
  • 空行,被认为是对第一个序列的最后一个元素的注释,需要移动该注释
  • 您的序列缩进不是默认的
  • the capitalization of dancing incorrect. To correct that, add a line handling the list if there is only one element
  • the code for the name Max, needs to be added (and that is why you need to get rid of the break in your code)
  • the empty line, is considered a comment on the last element of the first sequence, that comment needs to be moved
  • your indentation of sequences is non-default

最终代码如下:

from pathlib import Path
import ruamel.yaml

path = Path('input.yaml')
yaml = ruamel.yaml.YAML()
yaml.indent(sequence=4, offset=2)  # for the non-default indentation of sequences

data = yaml.load(path)
for key in data:
    value = data[key]
    if value['name'] == 'Stuart':
         if len(value['hobbies']) == 1:
             value['hobbies'][0] = value['hobbies'][0].capitalize()
         value['hobbies'].append('Fishing')
    elif value['name'] == 'Max':
         last_item_index = len(value['hobbies']) - 1
         value['hobbies'].append('Painting')
         comments = value['hobbies'].ca
         if not comments.items[last_item_index][0].value.strip():
             # move empty comment lines from previous last item to new last item
             comments.items[last_item_index + 1] = comments.items.pop(last_item_index)

yaml.dump(data, path)

这给出了非常接近你想要得到的东西

Which gives something quite close to what you wanted to get

team_member:
  name: Max
  hobbies:
    - Reading
    - Painting

team_leader:
  name: Stuart
  hobbies:
    - Dancing
    - Fishing

<小时>

¹前两行的替代方案:for key, value in data.items()

这篇关于如何读取 YAML 文件中的组件,以便我可以使用 ruamel.yaml 编辑它的键值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆