如何将Jinja模板化YAML文件转换为等效Jinja模板化JSON文件?
带Jinja模板语法的YAML转等效JSON解决方案
核心思路
要实现保留Jinja模板逻辑的YAML转JSON,核心是拆分模板标签与纯YAML内容,分别处理后再拼接,而非先渲染模板再转换。以下是三种可行方案:
方案一:基于Jinja AST解析转换
Jinja本身支持将模板解析为抽象语法树(AST),通过遍历AST节点,区分模板控制节点(if/for等)和纯文本节点(YAML内容),对文本节点做YAML→JSON语法转换,模板节点原样保留位置。
步骤
- 解析模板为AST:用Jinja的
Environment.parse()将带模板的YAML字符串解析为AST节点树。 - 遍历AST节点:
- 遇到
TemplateData节点(纯YAML文本):将文本片段解析为YAML对象,转换为对应JSON语法(比如给键加引号、调整缩进与大括号)。 - 遇到
If/For等控制节点:直接保留原Jinja标签,递归遍历节点内的子内容。
- 遇到
- 拼接结果:将处理后的文本片段与模板标签按原顺序拼接,保证JSON语法合法。
方案二:分段拆分+语法映射
将原文件按Jinja模板标签切割为纯YAML片段和模板片段,分别处理后重新组合:
步骤
- 拆分内容:用正则表达式匹配
{% ... %}标签,将原YAML分割为模板片段和纯YAML片段的列表。 - 转换YAML片段:对每个纯YAML片段,做语法映射:
- YAML键(如
foo:)转成JSON带引号的键("foo":)。 - YAML的缩进层级对应JSON的大括号包裹(如YAML中缩进的
bar:10要放在"foo": { ... }内部)。
- YAML键(如
- 拼接片段:按原顺序将模板片段插入转换后的JSON片段中,补全JSON的结构符号(如大括号、逗号)。
方案三:自定义模板转换器(代码示例)
结合Jinja、PyYAML和JSON模块,编写自定义转换器处理复杂场景:
from jinja2 import Environment from jinja2.nodes import TemplateData, If, Output import re def convert_jinja_yaml_to_json(jinja_yaml): env = Environment() ast = env.parse(jinja_yaml) result_parts = [] def process_node(node): if isinstance(node, TemplateData): # 处理纯YAML文本,转换为JSON语法片段 yaml_text = node.data.strip() if not yaml_text: return # 基础语法替换:YAML键转JSON带引号键 json_text = re.sub(r'^(\w+):', r'"\1":', yaml_text) # 处理嵌套块(如示例中的foo: 下的缩进内容) if json_text.startswith('"foo":'): json_text = json_text.replace('"foo":', '"foo": {') + '}' # 处理子键的引号 json_text = re.sub(r' (\w+):', r' "\1":', json_text) result_parts.append(json_text) elif isinstance(node, If): # 保留if-else标签 test_expr = node.test.as_const() result_parts.append(f"{{%- if {test_expr} %}}") for child in node.body: process_node(child) if node.else_: result_parts.append("{{%- else %}}") for child in node.else_: process_node(child) result_parts.append("{{%- endif %}}") elif isinstance(node, Output): for child in node.nodes: process_node(child) process_node(ast) return '\n'.join(result_parts) # 示例测试 sample_yaml = """foo: {%- if USE_10 %} bar: 10 {%- else %} bar: 20 {%- endif %}""" print(convert_jinja_yaml_to_json(sample_yaml))
注意事项
- 处理嵌套循环/条件时,需额外处理JSON的结构符号(如数组的逗号、大括号的闭合),避免语法错误。
- 对Jinja变量插值(如
{{ var }}),要保证其在JSON中的位置合法(比如字符串值内的插值需保留引号)。 - 复杂场景下需补充对
For节点的处理,循环生成JSON数组元素时要添加逗号判断(如{% if not loop.last %},{% endif %})。
内容的提问来源于stack exchange,提问作者danny
相关产品推荐
相关产品推荐

