为了账号安全,请及时绑定邮箱和手机立即绑定

如何在python中解析深度嵌套的yaml数据结构

如何在python中解析深度嵌套的yaml数据结构

慕侠2389804 2022-01-05 13:18:58
我们有一个 YAML 文件,它看起来有点像以下内容:all:  children:    allnetxsites:      children:        netxsites:          hosts:            bar.:              ansible_ssh_host: bart.j              domain: bart.local.domain              nfs: lars.local.domain我将如何获取bar.密钥的值和值nfs?蟒蛇代码:import yamlwith 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.domainNFS: lars.local.domain
查看完整描述

2 回答

?
莫回无

TA贡献1865条经验 获得超7个赞

你的标题让你看起来对正在发生的事情有点困惑,或者至少对术语有点困惑:虽然“YAML 数据结构”可能被解释为“从 YAML 文档加载的 Python 数据结构”的简写,但你没有进一步解析那个数据结构。任何解析都是作为 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因为代码段中版本中的列表处理 不正确。


尽管使用的标量类型不会影响递归查找,但您可能需要一个更通用的解决方案,它可以处理带有(嵌套)序列、标记节点和复杂映射键的 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.


上面提到的片段,@aaaaa 正在使用的片段,由于(直接)嵌套的序列/列表,将在加载的 YAML 上中断


查看完整回答
反对 回复 2022-01-05
?
泛舟湖上清波郎朗

TA贡献1818条经验 获得超3个赞

也许这个片段会给你一些帮助


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)


查看完整回答
反对 回复 2022-01-05
  • 2 回答
  • 0 关注
  • 284 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信