如何读取 YAML 文件中的组件以便我可以使用 ruamel.yaml 编辑它的键值?
How to read a component in YAML file so that I can edit it's key value using ruamel.yaml?
这是我的 YAML 文件 (input.yaml
):
team_member:
name: Max
hobbies:
- Reading
team_leader:
name: Stuart
hobbies:
- dancing
我想编辑此 YAML 文件以在键 'hobbies' 中添加更多值,示例:
team_member:
name: Max
hobbies:
- Reading
- Painting
team_leader:
name: Stuart
hobbies:
- Dancing
- Fishing
我尝试实现代码 Anthon 以适应我的情况,但它根本没有帮助,因为该 YAML 文件的缩进级别与我的不同。
示例:
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 的新手。
如何编码?
显示的错误消息中缺少的是行号(我假设它是 9)。指向行
if elem['name'] == 'Stuart':
如果这没有给您线索,我在这种情况下推荐的方法是开始添加一些 print
函数,以便您知道自己在做什么。 for
循环看起来像:
for elem in data:
print('elem', elem)
if elem['name'] == 'Stuart':
print('elem->hobbies', elem['hobbies'])
elem['hobbies'] = ['Fishing']
这会打印
elem team_member
在抛出异常之前,我希望这会让你意识到你不是在遍历列表的 elements(项目),而是遍历 keys of a dict(从 YAML 中的根级映射构建)。与键相关联的 value 是具有键 name
和键 hobbies
.
的对象
因此,将变量 elem
更改为 key
以明确您正在处理的内容,然后继续使用 value
,与该键关联的值而不是 elem
在该循环中¹:
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
所以我们去掉了异常,但是结果并不是你想要的。键 'hobbies' 的元素 dancing
消失了,因为您为该键分配了一个新的(列表)值,而您应该做的是将单个项目附加到列表中。我们现在也可以摆脱打印功能:
for key in data:
value = data[key]
if value['name'] == 'Stuart':
value['hobbies'].append('Fishing')
这将使您在文件的最终序列中得到两个项目。还有一些事情需要解决:
dancing
的大小写不正确。要更正此问题,请在只有一个元素时添加一行处理列表
- 需要添加名称
Max
的代码(这就是为什么您需要删除代码中的 break
)
- 空行,被认为是对第一个序列的最后一个元素的注释,需要移动该注释
- 您的序列缩进不是默认的
最终代码如下:
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)
它给出的东西非常接近你想要得到的东西
team_member:
name: Max
hobbies:
- Reading
- Painting
team_leader:
name: Stuart
hobbies:
- Dancing
- Fishing
¹前两行的替代方案:for key, value in data.items()
感谢 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)
这是我的 YAML 文件 (input.yaml
):
team_member:
name: Max
hobbies:
- Reading
team_leader:
name: Stuart
hobbies:
- dancing
我想编辑此 YAML 文件以在键 'hobbies' 中添加更多值,示例:
team_member:
name: Max
hobbies:
- Reading
- Painting
team_leader:
name: Stuart
hobbies:
- Dancing
- Fishing
我尝试实现代码 Anthon 以适应我的情况,但它根本没有帮助,因为该 YAML 文件的缩进级别与我的不同。
示例:
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 的新手。
如何编码?
显示的错误消息中缺少的是行号(我假设它是 9)。指向行
if elem['name'] == 'Stuart':
如果这没有给您线索,我在这种情况下推荐的方法是开始添加一些 print
函数,以便您知道自己在做什么。 for
循环看起来像:
for elem in data:
print('elem', elem)
if elem['name'] == 'Stuart':
print('elem->hobbies', elem['hobbies'])
elem['hobbies'] = ['Fishing']
这会打印
elem team_member
在抛出异常之前,我希望这会让你意识到你不是在遍历列表的 elements(项目),而是遍历 keys of a dict(从 YAML 中的根级映射构建)。与键相关联的 value 是具有键 name
和键 hobbies
.
因此,将变量 elem
更改为 key
以明确您正在处理的内容,然后继续使用 value
,与该键关联的值而不是 elem
在该循环中¹:
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
所以我们去掉了异常,但是结果并不是你想要的。键 'hobbies' 的元素 dancing
消失了,因为您为该键分配了一个新的(列表)值,而您应该做的是将单个项目附加到列表中。我们现在也可以摆脱打印功能:
for key in data:
value = data[key]
if value['name'] == 'Stuart':
value['hobbies'].append('Fishing')
这将使您在文件的最终序列中得到两个项目。还有一些事情需要解决:
dancing
的大小写不正确。要更正此问题,请在只有一个元素时添加一行处理列表- 需要添加名称
Max
的代码(这就是为什么您需要删除代码中的break
) - 空行,被认为是对第一个序列的最后一个元素的注释,需要移动该注释
- 您的序列缩进不是默认的
最终代码如下:
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)
它给出的东西非常接近你想要得到的东西
team_member:
name: Max
hobbies:
- Reading
- Painting
team_leader:
name: Stuart
hobbies:
- Dancing
- Fishing
¹前两行的替代方案:for key, value in data.items()
感谢 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)