你的标题让你看起来对什么是有点困惑
继续,或者至少关于术语:虽然“YAML 数据
结构”可能被解释为“Python 数据结构”的简写
从 YAML 文档加载”,您无需进一步解析该数据
结构体。任何解析都是作为 YAML 加载的一部分完成的
文档和解析甚至在yaml.load() 之前就已经完全完成
返回。作为加载的结果,您在 Python 中有一个数据结构,并且
你“只是”需要在嵌套的 Python 数据结构中查找一个键
递归遍历该数据结构。
你的 YAML 例子有点无趣,因为它只代表一个
真实 YAML 的一小部分,因为您的 YAML 仅包含(普通)标量
它们是标量的字符串、映射和映射键。
为了遍历该数据结构,提供了递归函数@aaaaaa 的简化版本
会做的:
import sys
import yaml
yaml_str = """\
all:
children:
allnetxsites:
children:
netxsites:
hosts:
bar.:
ansible_ssh_host: bart.j
domain: bart.local.domain
nfs: lars.local.domain
"""
data = yaml.safe_load(yaml_str)
def find(key, dictionary):
# everything is a dict
for k, v in dictionary.items():
if k == key:
yield v
elif isinstance(v, dict):
for result in find(key, v):
yield result
for x in find("nfs", data):
print(x)
打印预期的:
lars.local.domain
我已经简化了函数find,因为在版本中的列表处理
snippet 不正确。
虽然使用的标量种类不影响递归查找,
您可能想要一个更通用的解决方案来处理 YAML
(嵌套)序列、标记节点和复杂的映射键。
假设您的输入文件稍微复杂一点input.yaml:
all:
{a: x}: !xyz
- [k, l, 0943]
children:
allnetxsites:
children:
netxsites:
hosts:
bar.:
ansible_ssh_host: bart.j
domain: bart.local.domain
nfs: lars.local.domain
你可以使用ruamel.yaml(免责声明:我是那个包的作者)来做:
import sys
from pathlib import Path
import ruamel.yaml
in_file = Path('input.yaml')
yaml = ruamel.yaml.YAML()
data = yaml.load(in_file)
def lookup(sk, d, path=[]):
# lookup the values for key(s) sk return as list the tuple (path to the value, value)
if isinstance(d, dict):
for k, v in d.items():
if k == sk:
yield (path + [k], v)
for res in lookup(sk, v, path + [k]):
yield res
elif isinstance(d, list):
for item in d:
for res in lookup(sk, item, path + [item]):
yield res
for path, value in lookup("nfs", data):
print(path, '->', value)
给出:
['all', 'children', 'allnetxsites', 'children', 'netxsites', 'hosts', 'bar.', 'nfs'] -> lars.local.domain
由于 PyYAML 只解析 YAML 1.1 的一个子集并且加载更少的
也就是说,它无法处理 input.yaml 中的有效 YAML。
上面提到的sn-p,@aaaaa 正在使用的那个,将会中断
由于(直接)嵌套的序列/列表而加载的 YAML