[英]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:还有一些事情要解决:
dancing
incorrect. dancing
的大小写不正确。 To correct that, add a line handling the list if there is only one element要纠正这一点,如果只有一个元素,请添加一行处理列表Max
, needs to be added (and that is why you need to get rid of the break
in your code)需要添加名称Max
的代码(这就是为什么您需要摆脱代码中的break
)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.