我正在使用Python开发一个软件,我需要读取多个级别的YAML文件,如下所示:
#Filename: SampleCase.yml
%YAML 1.1
VesselTypes:
- Name: Escort Tug
Length: 32
Breadth: 12.8
Depth: 9
Draughts:
- Name: Draught1
Mass: 500
CentreOfGravity: [16.497, 0, 4.32]
TowingStaples:
- Name: Staple1
Position: [0, 0, 0]
Thrusters:
- Name: Port Propeller
Position: [0, -1, 0]
MaxRPM: 1800
MaxPower: 2525
- Name: Stbd Propeller
Position: [0, 1, 0]
MaxRPM: 1800
MaxPower: 2525
- Name: Ship
Vessels:
- Name: Tug
VesselType: Escort Tug
Draught: Draught1
InitialPosition: [0, 0, 0]
Orientation: [0, 0, 0]
- Name: Tanker
VesselType: Ship
Draught: Draught1
InitialPosition: [0, 0, 0]
Orientation: [0, 0, 0]
Speed: 8
这里有两艘名为Tug and Tanker的船只。它们有两种类型,“Escort Tug”和“Ship”。
#Filename: main.py
import yaml
# Reading YAML data
file_name = 'SampleCase.yml'
with open(file_name, 'r') as f:
data = yaml.load(f)
print(data["Vessels"][0]["Name"])
我能够使用索引号访问存储的数据(例如data["Vessels"][0]["Name"]
,但我想使用匹配键访问它们。例如,我想打印端口螺旋桨的MaxRPM值名为“Tug”的船。在python中执行此操作的标准方法是什么?
答案 0 :(得分:1)
没有一种标准的方法可以做到这一点,这在很大程度上是由于YAML的键可能很复杂。这使得路径匹配方法适用于更简单的格式,如JSON不可用。
如果您的YAML是“无标记”,与您的一样,它仍然允许比JSON更复杂的结构,但是您可以相当容易地在YAML文件的集合类型(序列和映射)上递归地实现步行,而这样做明确匹配索引resp。键和/或元素resp。值:
import ruamel.yaml as yaml
def _do_not_care():
pass
def find_collection(d, key=_do_not_care, value=_do_not_care, results=None):
def check_key_value(d, k, v, results):
# print('checking', key, value, k, d[k], results)
if k == key:
if value in [_do_not_care, v]:
results.append(d)
return
elif key == _do_not_care and v == value:
results.append(d)
return
if isinstance(v, (dict, list)):
find_collection(v, key, value, results)
if results is None:
results = []
if isinstance(d, dict):
for k in d:
check_key_value(d, k, d[k], results)
if isinstance(d, list):
for k, v in enumerate(d):
check_key_value(d, k, v, results)
return results
def find_first(d, key=_do_not_care, value=_do_not_care):
ret_val = find_collection(d, key, value)
return ret_val[0] if ret_val else {}
def find_value_for_key(d, key):
return find_first(d, key)[key]
如上所述,您可以这样做:
file_name = 'SampleCase.yml'
with open(file_name, 'r') as f:
data = yaml.safe_load(f)
for d in find_collection(data, value='Tug'):
vessel_type = find_first(data, key='Name', value=d['VesselType'])
port_propeller = find_first(vessel_type, key='Name', value='Port Propeller')
print('Tug -> MaxRPM', find_value_for_key(port_propeller, key='MaxRPM'))
此打印(假设输入已更正,请参见第1点):
Tug -> MaxRPM 1800
有几点需要注意:
您的YAML无效,因为指令和文档之间没有---
分隔。前三行看起来应该是这样的:
%YAML 1.1
---
VesselTypes:
然而,可能根本没有必要指定该指令:PyYAML在七年后仍然不支持YAML 1.2并且您的YAML似乎没有YAML 1.1特定的任何内容。
您使用的是没有load()
参数的PyYAML Loader
,如果您无法控制输入,则可能不安全。如果可以,您应该始终使用safe_load
(与您的来源一样)。
上面的测试使用ruamel.yaml
(PyYAML的超集支持YAML 1.2以及1.1。免责声明:我是该软件包的作者)。如果你必须坚持下去,我应该像PyYAML一样工作。
答案 1 :(得分:0)
您可以将YAML输出传递给function,该函数根据您的特定搜索要求构造字典。你描述的行为听起来很特别,我认为没有任何内置的东西可供使用。
答案 2 :(得分:0)
将您的list
变为dict
,其中的键是名称:
result = {}
for elem in data['Vessels']:
name = elem.pop('Name')
result[name] = elem
data['Vessels'] = result
print(data['Tug'])
>> {'VesselType': 'EscortTug ...}