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

如何将Jinja模板化YAML文件转换为等效Jinja模板化JSON文件?

带Jinja模板语法的YAML转等效JSON解决方案

核心思路

要实现保留Jinja模板逻辑的YAML转JSON,核心是拆分模板标签与纯YAML内容,分别处理后再拼接,而非先渲染模板再转换。以下是三种可行方案:


方案一:基于Jinja AST解析转换

Jinja本身支持将模板解析为抽象语法树(AST),通过遍历AST节点,区分模板控制节点(if/for等)和纯文本节点(YAML内容),对文本节点做YAML→JSON语法转换,模板节点原样保留位置。

步骤

  1. 解析模板为AST:用Jinja的Environment.parse()将带模板的YAML字符串解析为AST节点树。
  2. 遍历AST节点:
    • 遇到TemplateData节点(纯YAML文本):将文本片段解析为YAML对象,转换为对应JSON语法(比如给键加引号、调整缩进与大括号)。
    • 遇到If/For等控制节点:直接保留原Jinja标签,递归遍历节点内的子内容。
  3. 拼接结果:将处理后的文本片段与模板标签按原顺序拼接,保证JSON语法合法。

方案二:分段拆分+语法映射

将原文件按Jinja模板标签切割为纯YAML片段和模板片段,分别处理后重新组合:

步骤

  1. 拆分内容:用正则表达式匹配{% ... %}标签,将原YAML分割为模板片段和纯YAML片段的列表。
  2. 转换YAML片段:对每个纯YAML片段,做语法映射:
    • YAML键(如foo:)转成JSON带引号的键("foo":)。
    • YAML的缩进层级对应JSON的大括号包裹(如YAML中缩进的bar:10要放在"foo": { ... }内部)。
  3. 拼接片段:按原顺序将模板片段插入转换后的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 10:20:30