yaml锚定定义加载到PyYAML中

adi*_*adi 3 python yaml pyyaml

我正在使用PyYAML。有没有一种方法可以定义YAML锚,而不会成为yaml.load加载的数据结构的一部分(我可以从字典中删除“ wifi_parm”,但正在寻找一种更智能的方法)?

example.yaml

wifi_parm: &wifi_params
  ssid: 1
  key: 2
test1:
  name: connectivity
  <<: *wifi_params
test2:
  name: connectivity_5ghz
  <<: *wifi_params
Run Code Online (Sandbox Code Playgroud)

load_example.py

import yaml
import pprint

with open('aaa.yaml', 'r') as f:
    result = yaml.load(f)
pprint.pprint(result)
Run Code Online (Sandbox Code Playgroud)

印刷品:

{'test1': {'key': 2, 'name': 'connectivity', 'ssid': 1},
 'test2': {'key': 2, 'name': 'connectivity_5ghz', 'ssid': 1},
 'wifi_parm': {'key': 2, 'ssid': 1}}
Run Code Online (Sandbox Code Playgroud)

我需要:

{'test1': {'key': 2, 'name': 'connectivity', 'ssid': 1},
 'test2': {'key': 2, 'name': 'connectivity_5ghz', 'ssid': 1}}
Run Code Online (Sandbox Code Playgroud)

Ant*_*hon 5

在从中获取结果之前,将丢弃PyYAML中的锚信息yaml.load()。这是根据PyYAML遵循的YAML 1.1规范(...锚名称是序列化详细信息,一旦编写完成就将其丢弃)。在YAML 1.2规范(自2009年起)中,这没有更改。您不能在PyYAML中通过result(递归地)遍历并测试哪些值可能是锚点来执行此操作,而无需大量修改解析器。

在我的ruamel.yaml(即YAML 1.2)的往返模式中,我保留了实际用于别名映射或序列的锚的锚和别名(锚别名目前不为标量保留,也没有“未使用”锚):

import ruamel.yaml

with open('aaa.yaml') as f:
    result = ruamel.yaml.round_trip_load(f)

ruamel.yaml.round_trip_dump(result, sys.stdout)
Run Code Online (Sandbox Code Playgroud)

给出:

wifi_parm: &wifi_params
  ssid: 1
  key: 2
test1:
  <<: *wifi_params
  name: connectivity
test2:
  <<: *wifi_params
  name: connectivity_5ghz
Run Code Online (Sandbox Code Playgroud)

您实际上可以遍历映射(或递归地映射树)并找到锚点节点并删除它,而无需知道键名。

import ruamel.yaml
from ruamel.yaml.comments import merge_attrib

with open('aaa.yaml') as f:
    result = ruamel.yaml.round_trip_load(f)

keys_to_delete = []
for k in result:
    v = result[k]
    if v.yaml_anchor():
        keys_to_delete.append(k)
    for merge_data in v.merge:  # update the dict with the merge data 
        v.update(merge_data[1])
        delattr(v, merge_attrib)
for k in keys_to_delete:
    del result[k]

ruamel.yaml.round_trip_dump(result, sys.stdout)
Run Code Online (Sandbox Code Playgroud)

给出:

test1:
  name: connectivity
  ssid: 1
  key: 2
test2:
  name: connectivity_5ghz
  ssid: 1
  key: 2
Run Code Online (Sandbox Code Playgroud)

也可以一般地和递归地执行此操作(即,对于树中任意位置的锚和别名)。更新将和上面一样容易,但是您需要跟踪如何删除键,并且不必一定是映射值,它可以是一个序列项。