如何处理YAML:解析锚点指针且保留!flatten与!ref标签
问题概述
需要处理一段YAML代码,实现两个核心需求:
- 解析并展开YAML中的锚点指针(如
<<: *ip_context这种合并键) - 保留
!flatten和!ref自定义标签,确保后续程序能识别处理
输入YAML
_ip_context: &ip_context ip_restriction: !flatten - !ref 'constant::public_cidr_blocks' policies: - file: policies/somepolicy.json context: <<: *ip_context
期望输出
policies: - file: policies/somepolicy.json context: ip_restriction: !flatten - !ref 'constant::public_cidr_blocks'
现有代码的问题
之前的代码存在以下缺陷:
- 将所有
list类型都映射为!flatten标签,所有str类型都映射为!ref标签,导致逻辑错误 - 没有移除原始的
_ip_context锚点定义,输出中保留了不必要的内容 - 没有正确展开合并键,反而生成了新的锚点引用,不符合期望
正确解决方案
通过自定义类型封装标签信息,精准处理锚点展开和标签保留,代码如下:
import sys import yaml # 自定义类封装!flatten和!ref类型,避免与普通list/str混淆 class Flatten: def __init__(self, data): self.data = data class Ref: def __init__(self, data): self.data = data # 自定义构造函数,解析标签并转为对应自定义类实例 class CustomLoader(yaml.SafeLoader): def construct_flatten(self, node): seq = self.construct_sequence(node) return Flatten(seq) def construct_ref(self, node): scalar = self.construct_scalar(node) return Ref(scalar) CustomLoader.add_constructor('!flatten', CustomLoader.construct_flatten) CustomLoader.add_constructor('!ref', CustomLoader.construct_ref) # 自定义表示器,将自定义类转为对应YAML标签 class CustomDumper(yaml.SafeDumper): def represent_flatten(self, data): return self.represent_sequence('!flatten', data.data) def represent_ref(self, data): return self.represent_scalar('!ref', data.data) CustomDumper.add_representer(Flatten, CustomDumper.represent_flatten) CustomDumper.add_representer(Ref, CustomDumper.represent_ref) # 加载YAML内容 yaml_content = """ _ip_context: &ip_context ip_restriction: !flatten - !ref 'constant::public_cidr_blocks' policies: - file: policies/somepolicy.json context: <<: *ip_context """ data = yaml.load(yaml_content, Loader=CustomLoader) # 移除原始锚点定义 del data['_ip_context'] # 展开policies中的合并键 for policy in data['policies']: if '<<' in policy['context']: # 获取锚点对应的内容(加载时已自动解析为实际数据) merged_data = policy['context']['<<'] # 删除合并键,合并内容到context del policy['context']['<<'] policy['context'].update(merged_data) # 输出处理后的YAML yaml.dump( data, sys.stdout, default_flow_style=False, Dumper=CustomDumper, sort_keys=False # 保持原有的键顺序 )
关键说明
- 自定义类型封装:用
Flatten和Ref类分别包裹对应标签的数据,避免与普通列表、字符串混淆,确保dump时能精准识别并输出标签。 - 锚点展开处理:加载后手动移除合并键
<<,将锚点对应的实际数据合并到context中,实现完全展开。 - 保留键顺序:通过
sort_keys=False确保输出的键顺序与原始输入一致,符合预期格式。 - 禁用默认锚点:自定义表示器避免了自动生成新的锚点引用,输出为完全展开的内容。
内容的提问来源于stack exchange,提问作者Jeff Saremi
相关产品推荐
相关产品推荐

