简体   繁体   English

如何读取 YAML 文件中的组件以便我可以使用 ruamel.yaml 编辑它的键值?

[英]How to read a component in YAML file so that I can edit it's key value using ruamel.yaml?

This is my YAML file ( input.yaml ):这是我的 YAML 文件( input.yaml ):

team_member:
  name: Max
  hobbies:
    - Reading

team_leader:
  name: Stuart
  hobbies:
    - dancing

I want to edit this YAML file to add more values in key 'hobbies', example:我想编辑此 YAML 文件以在关键“爱好”中添加更多值,例如:

team_member:
  name: Max
  hobbies:
    - Reading
    - Painting

team_leader:
  name: Stuart
  hobbies:
    - Dancing
    - Fishing

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.我尝试实现代码Anthon以适应我的情况,但它根本没有帮助,因为该 YAML 文件的缩进级别与我的不同。
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)

I get error "TypeError('string indices must be integers',)", I know this code might be completely wrong, but I am new to ruamel.yaml.我收到错误“TypeError('字符串索引必须是整数',)”,我知道这段代码可能完全错误,但我是 ruamel.yaml 的新手。

How to code this?如何编码?

The thing missing form the error message displayed is the line number (I assume that it is 9).显示的错误消息中缺少的是行号(我假设它是 9)。 That points to the line那指向那条线

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

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.如果这没有给您任何线索,那么我在这种情况下推荐的方法是开始添加一些print功能,以便您知道自己在做什么。 The for loop looks like: for循环如下所示:

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

this prints这打印

 elem team_member

before the exception is thrown, and I hope that will make you realize your are not iterating over the elem ents (items) of a list, but over the key s of a dict (constructed from the root level mapping in your YAML).在抛出异常之前,我希望这会让您意识到您不是在迭代列表的元素(项目),而是在 dict 的键上迭代(从 YAML 中的根级映射构建)。 And the value associated with the key is the object having a key name and a key hobbies .与键关联的是具有键name和键hobbies

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

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

This gives:这给出:

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

team_leader:
  name: Stuart
  hobbies:
  - Fishing

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.为关键“爱好” dancing的元素消失了,因为您为该键分配了一个新的(列表)值,而您应该做的是将单个项目附加到列表中。 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:还有一些事情要解决:

  • the capitalization of dancing incorrect. dancing的大小写不正确。 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)需要添加名称Max的代码(这就是为什么您需要摆脱代码中的break
  • 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您的序列缩进是非默认的

The final code would be like:最终代码如下:

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

¹ Alternative for the first two lines: for key, value in data.items() ¹前两行的替代方法: for key, value in data.items()

Thanks Anthon your code worked I have to edit this code as follows:感谢 Anthon,您的代码有效,我必须按如下方式编辑此代码:

import sys
import ruamel.yaml
from pathlib import Path

yaml = ruamel.yaml.YAML()
path = Path('input.yaml')
yaml.indent(sequence=4, offset=2)  # for the non-default indentation of sequences
with open(path) as fp:
    data = yaml.load(fp)
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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用 ruamel.yaml 包编辑 yaml 文件,而不更改文件的缩进? - How do I edit a yaml file using ruamel.yaml package, without changing the indentation of the file? 如何使用ruamel.yaml而不是pyyaml通过python编辑YAML文件? - How do I edit a YAML file through python using ruamel.yaml and not pyyaml? 如何在Python中使用ruamel.yaml从YAML文件中获取注释? - How can I get comments from a YAML file using ruamel.yaml in Python? 如何使用 ruamel.yaml 将内容添加到 YAML 文件? - How to add contents to YAML file using ruamel.yaml? 如何使用 ruamel.yaml 在 YAML 中插入换行符? - How can I insert linebreak in YAML with ruamel.yaml? 如何在Python的ruamel.yaml中的空yaml文件中插入键值对? - How to insert a key value pair in an empty yaml file in ruamel.yaml in Python? 如何使用 ruamel.yaml 在 YAML 文件中保留或添加值周围的引号而不剥离注释作为副作用? - How can I preserve or add quotes around values in a YAML file without stripping comments as a side effect using ruamel.yaml? 使用 ruamel.yaml 时,如何防止重新格式化 yaml 文件? - How can I prevent re-formating of a yaml file when ruamel.yaml is used? 我可以在ruamel.yaml的CommentedMap中插入一行吗? - Can I insert a line into ruamel.yaml's CommentedMap? 如何使用ruamel.yaml添加评论 - How can I add a comment with ruamel.yaml
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM