解析YAML并假设某个路径始终为字符串
我正在使用来自 http://pyyaml.org 的 YAML 解析器,我希望它总是把某些字段当作字符串来处理,但我搞不清楚 add_path_resolver() 是怎么工作的。
举个例子:解析器会把 "version" 当作浮点数来处理:
network:
- name: apple
- name: orange
version: 2.3
site: banana
有些文件里有 "version: 2"(这被当作整数处理)或者 "version: 2.3 alpha"(这被当作字符串处理)。
我希望它们总是被当作字符串处理。
看起来 yaml.add_path_resolver() 应该可以让我指定,“当你看到 version: 时,总是把它当作字符串处理”,但这个功能的文档写得不太清楚。我的最佳猜测是:
yaml.add_path_resolver(u'!root', ['version'], kind=str)
但是这样并不奏效。
有没有什么建议可以让我确保 version 字段总是被当作字符串处理?
附注:这里有一些不同的 "version" 字符串及其被解析的方式:
(Pdb) import yaml
(Pdb) import pprint
(Pdb) pprint.pprint(yaml.load("---\nnetwork:\n- name: apple\n- name: orange\nversion: 2\nsite: banana"))
{'network': [{'name': 'apple'}, {'name': 'orange'}],
'site': 'banana',
'version': 2}
(Pdb) pprint.pprint(yaml.load("---\nnetwork:\n- name: apple\n- name: orange\nversion: 2.3\nsite: banana"))
{'network': [{'name': 'apple'}, {'name': 'orange'}],
'site': 'banana',
'version': 2.2999999999999998}
(Pdb) pprint.pprint(yaml.load("---\nnetwork:\n- name: apple\n- name: orange\nversion: 2.3 alpha\nsite: banana"))
{'network': [{'name': 'apple'}, {'name': 'orange'}],
'site': 'banana',
'version': '2.3 alpha'}
2 个回答
2
根据目前的源代码:
# Note: `add_path_resolver` is experimental. The API could be changed.
看起来这个还不完整(还没完成?)。我能想到的有效语法是:
yaml.add_path_resolver(u'tag:yaml.org,2002:str', ['version'], yaml.ScalarNode)
但是,它并没有按预期工作。
似乎系统首先会检查隐式类型解析器,如果有匹配的,就不会再检查用户自定义的解析器。想了解更多细节,可以查看resolver.py,找找resolve
这个函数。
我建议你把version
的内容改成:
version: !!str 2.3
这样做会确保它总是被转换成字符串。
1
到目前为止,最简单的解决办法就是不要使用基本的 .load()
方法(反正这个方法也不安全),而是用 Loader=BaseLoader
,这样可以把每个标量值都当作字符串来加载:
import yaml
yaml_str = """\
network:
- name: apple
- name: orange
version: 2.3
old: 2
site: banana
"""
data = yaml.load(yaml_str, Loader=yaml.BaseLoader)
print(data)
结果是:
{'network': [{'name': 'apple'}, {'name': 'orange'}], 'version': '2.3', 'old': '2', 'site': 'banana'}