You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何处理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  # 保持原有的键顺序
)

关键说明

  1. 自定义类型封装:用Flatten和Ref类分别包裹对应标签的数据,避免与普通列表、字符串混淆,确保dump时能精准识别并输出标签。
  2. 锚点展开处理:加载后手动移除合并键<<,将锚点对应的实际数据合并到context中,实现完全展开。
  3. 保留键顺序:通过sort_keys=False确保输出的键顺序与原始输入一致,符合预期格式。
  4. 禁用默认锚点:自定义表示器避免了自动生成新的锚点引用,输出为完全展开的内容。

内容的提问来源于stack exchange,提问作者Jeff Saremi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 05:43:19