如何让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
相关产品推荐
相关产品推荐

