如何访问PyYAML的yaml文件中的映射值?

时间:2017-02-10 16:46:41

标签: python dictionary yaml pyyaml

假设我有一个如下所示的YAML文件:

food:
  fruits: 
    round: apple
    big: watermelon
  grain: wheat
  vegetable: cabbage

我希望能够在YAML文档中编写等效的python代码tasty = food['fruits']['round'](将解析为apple)。

我可以参考一个变量,因此我可以做到

food: &FOOD
  fruits: 
    round: apple
    big: watermelon
  grain: wheat
  vegetable: cabbage

然后引用整个地图,例如

something: *FOOD 

但是如何在YAML内部的地图地图中查找值?

2 个答案:

答案 0 :(得分:0)

您可以为单个值创建锚点:

import yaml


def main():
    yf = """
    food:
      fruits: 
        round: &FOOD apple
        big: watermelon
      grain: wheat
      vegetable: cabbage
    something: *FOOD
    """

    print(yaml.load(yf))


if __name__ == '__main__':
    main()

打印:
{' food':{'蔬菜':'卷心菜'' grain':'小麦',' ;水果&#39 ;:
{'大':'西瓜','围绕':' apple'}},'东西':&# 39;苹果'}

答案 1 :(得分:0)

你可以这样做:

import sys
import ruamel.yaml

yaml_str = """\
food: &FOOD
  fruits:
    round: apple
    big: watermelon
  grain: [wheat, barley, spelt]
  vegetable: cabbage
something: $FOOD.fruits.big
otherthing: $.food.grain.2   # 2 -> third element
"""

def resolve(data, sep='.', initial='$'):
    """walk over tree and resolve strings that start with $
       $XYZ.abc -> resolve starting at anchor XYZ
       $.abc -> resolve starting at toplevel
    """
    def get_anchors(d, anchors):
        if isinstance(d, ruamel.yaml.comments.CommentedMap):
            if d.yaml_anchor() is not None:
                anchors[d.anchor.value] = d
            for k in d:
                get_anchors(d[k], anchors)
        elif isinstance(d, ruamel.yaml.comments.CommentedSeq):
            if d.yaml_anchor() is not None:
                anchors[d.anchor.value] = d
            for e in d:
                get_anchors(e, anchors)

    def resolvex(data, d, anchors, sep, initial):
        if isinstance(d, ruamel.yaml.comments.CommentedMap):
            for k in d:
                upd, val = resolvex(data, d[k], anchors, sep, initial)
                if upd:
                    d[k] = val
            return False, None
        elif isinstance(d, ruamel.yaml.comments.CommentedSeq):
            for idx, e in enumerate(d):
                upd, val = resolvex(data, e, anchors, sep, initial)
                if upd:
                    d[idx] = val
            return False, None
        if isinstance(d, str) and d and d[0] == initial:
            path = d[1:].split(sep)
            dx = data if path[0] == '' else anchors.get(path[0])
            while len(path) > 1:
                path = path[1:]
                if isinstance(dx, ruamel.yaml.comments.CommentedSeq):
                    dx = dx[int(path[0])]
                else:
                    dx = dx[path[0]]
            return True, dx
        return False, None

    anchors = {}
    get_anchors(data, anchors=anchors)
    resolvex(data, data, anchors, sep, initial)

data = ruamel.yaml.round_trip_load(yaml_str)
resolve(data)
ruamel.yaml.round_trip_dump(data, sys.stdout)

带输出:

food:
  fruits:
    round: apple
    big: watermelon
  grain: [wheat, barley, spelt]
  vegetable: cabbage
something: watermelon
otherthing: spelt            # 2 -> third element

请注意,您不能使用PyYAML执行上述操作,因为它不会保留锚名称,您必须使用ruamel.yaml(免责声明:我是该程序包的作者)。