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

如何让YAML保留重复键?求简洁替代配置格式

解决YAML重复键保留问题及替代配置格式方案

一、让YAML保留重复键的实现方法

YAML规范本身允许重复键,但多数解析器默认会覆盖后续值,可通过自定义构造器修改解析逻辑,将重复键的值自动合并为列表。

使用ruamel.yaml自定义构造器

from ruamel.yaml import YAML
from ruamel.yaml.constructor import SafeConstructor

def custom_construct_mapping(loader, node, deep=False):
    # 先收集所有键值对,避免覆盖
    mapping = []
    for key_node, value_node in node.value:
        key = loader.construct_object(key_node, deep=deep)
        value = loader.construct_object(value_node, deep=deep)
        mapping.append((key, value))
    
    # 转换为带列表的字典:重复键对应值转为列表,单个值保持原样
    result = {}
    for key, value in mapping:
        if key in result:
            if isinstance(result[key], list):
                result[key].append(value)
            else:
                result[key] = [result[key], value]
        else:
            result[key] = value
    return result

# 替换默认构造逻辑
SafeConstructor.construct_mapping = custom_construct_mapping

yaml = YAML(typ='safe')
yaml.allow_duplicate_keys = True  # 允许重复键,关闭默认警告

# 测试解析
yaml_content = """
div:
  class: container
  div:
    p: Hello
    p: World
"""
parsed_data = yaml.load(yaml_content)
print(parsed_data)
# 输出:{'div': {'class': 'container', 'div': {'p': ['Hello', 'World']}}}

使用PyYAML自定义构造器

import yaml
from yaml.constructor import SafeConstructor

def duplicate_key_constructor(loader, node):
    mapping = []
    yield mapping
    for key_node, value_node in node.value:
        key = loader.construct_object(key_node)
        value = loader.construct_object(value_node)
        mapping.append((key, value))

# 替换默认映射构造器
SafeConstructor.add_constructor(
    yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
    duplicate_key_constructor
)

# 转换原始列表为带重复键处理的字典
def convert_to_dict(mapping_list):
    result = {}
    for key, value in mapping_list:
        if isinstance(value, list):
            value = convert_to_dict(value)
        if key in result:
            if not isinstance(result[key], list):
                result[key] = [result[key]]
            result[key].append(value)
        else:
            result[key] = value
    return result

yaml_str = """
div:
  class: container
  div:
    p: Hello
    p: World
"""
raw_data = yaml.load(yaml_str, Loader=SafeConstructor)
final_data = convert_to_dict(raw_data)
print(final_data)
# 输出:{'div': {'class': 'container', 'div': {'p': ['Hello', 'World']}}}

二、替代配置格式推荐

如果不想修改YAML解析逻辑,可选择以下缩进友好、支持嵌套且能自然处理重复元素的格式:

1. 调整YAML写法(无额外依赖)

将重复键改为数组项,符合YAML规范且无需修改解析逻辑:

div:
  class: container
  div:
    - p: Hello
    - p: World

解析后div下的内容会是列表,可直接遍历生成多个<p>标签。

2. HCL(HashiCorp配置语言)

依赖缩进,支持复杂嵌套,可通过数组语法自然处理重复元素:

div {
  class = "container"
  div {
    p = ["Hello", "World"]
  }
}

Python可通过pyhcl库解析,语法简洁且无过多冗余符号。

3. 自定义缩进格式(轻量灵活)

如果现有格式需求特殊,可自定义极简缩进格式,比如:

div
  class: container
  div
    p: Hello
    p: World

自己实现简单的解析器(按缩进层级构建嵌套结构,重复键自动转为列表),完全适配你的HTML生成逻辑,无需依赖第三方库。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 18:40:34