我们有一个YAML文件,看起来类似于以下内容:
all:
children:
allnetxsites:
children:
netxsites:
hosts:
bar.:
ansible_ssh_host: bart.j
domain: bart.local.domain
nfs: lars.local.domain
我该如何获取值bar.
和键nfs
的值?
Python代码:
import yaml
with open("/Users/brendan_vandercar/sites.yaml", 'r') as stream:
data_loaded = yaml.load(stream)
for element in data_loaded:
name = "element"['all']['children']['allnetxsites']['children']['netxsites']['hosts']['bart']['nfs'][0]
print(name)
我想得到的是该脚本的清单输出,内容如下:
Domain: bart.local.domain
NFS: lars.local.domain
答案 0 :(得分:0)
也许this snippet会为您提供一些帮助
def find(key, dictionary):
for k, v in dictionary.iteritems():
if k == key:
yield v
elif isinstance(v, dict):
for result in find(key, v):
yield result
elif isinstance(v, list):
for d in v:
for result in find(key, d):
yield result
然后您的代码等同于
find('nfs', data_loaded)
答案 1 :(得分:0)
您的标题使您看起来对什么有点困惑
或至少与术语有关:尽管“ 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不正确。
尽管使用的标量类型不影响递归查找, 您可能想要一个更通用的解决方案,可以使用 (嵌套)序列,标记的节点以及复杂的映射键。
假设您的输入文件稍微复杂一点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。
上面提到的代码片段(@aaaaa正在使用)正在中断 由于(直接)嵌套了序列/列表,因此加载了YAML