将YAML文件加载到Python中并保留别名

3
我正在编写一个程序,需要检查某些字段是否使用了正确的别名字符串。例如:
networks:
  base: 
    name: build
    address: &dummyname
     url: 192.168.1.1
     port: 8080 
  first: 
    name: masterA
    address: *dummyname
  second: 
    name: masterB
    address: *dummyname

我需要检查字段address是否在第一和第二中以别名“*dummyname”定义,无论别名的内容是什么。

使用PyYaml执行加载时,总是会呈现别名,因此我无法检查:

data = yaml.safe_load(file_data)

Python 字典格式的数据:

networks:
  base: 
    name: build
    address: 
      url: 192.168.1.1
      port: 8080 
  first: 
    name: masterA
    address: 
      url: 192.168.1.1
      port: 8080 
  second: 
    name: masterB
    address: 
      url: 192.168.1.1
      port: 8080 

我看到了一些类似的帖子,介绍将python对象转换为YAML格式但不创建别名/锚点的方法,但我还没有找到这个问题的解决方案。

如何访问在YAML文档中使用的别名?

1个回答

1

正如您所指出的,PyYAML无法让您访问锚点/别名名称,它在内部使用它来解决这个问题。当您再次转储data时,您会注意到您得到了一个通用的锚点(例如&id0001)。

如果您使用ruamel.yaml以这种方式往返处理数据,您可以看到您实际的锚点/别名被保留:

import sys
import ruamel.yaml

file_in = Path('input.yaml')
    
yaml = ruamel.yaml.YAML()
data = yaml.load(file_in)
yaml.dump(data, sys.stdout)

因为这样会带来:

networks:
  base:
    name: build
    address: &dummyname
      url: 192.168.1.1
      port: 8080
  first:
    name: masterA
    address: *dummyname
  second:
    name: masterB
    address: *dummyname

您可以检查已加载的数据结构:

# you get the same object, whether using `first`, `second` or `base`
address = data['networks']['first']['address']
print(address, type(address))
print('\n'.join([k for k in dir(address) if k[0] != '_']))  # skip the build-in attributes

这将会提供:

ordereddict([('url', '192.168.1.1'), ('port', 8080)]) <class 'ruamel.yaml.comments.CommentedMap'>
add_referent
add_yaml_merge
anchor
ca
clear
copy
copy_attributes
fa
fromkeys
get
insert
items
keys
lc
merge
mlget
move_to_end
non_merged_items
pop
popitem
rya
setdefault
tag
update
update_key_value
values
yaml_add_eol_comment
yaml_anchor
yaml_end_comment_extend
yaml_key_comment_extend
yaml_set_anchor
yaml_set_comment_before_after_key
yaml_set_start_comment
yaml_set_tag
yaml_value_comment_extend

可能的候选项是属性anchor,实际上这是一个Anchor实例,在该实例上可以检索到原始字符串:
print(f'anchor: {address.anchor.value}')

提供:

anchor: dummyname

请注意,这些内部机制可能会发生变化,因此请锁定您正在使用的ruamel.yaml版本并在升级之前进行测试。

尝试了一下,确实有效。感谢您的帮助! - David Pascual

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接