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

如何更新包含Jinja2变量的多段YAML文件且保留原有Jinja语法

问题场景

我遇到的使用场景和Stack Overflow上的《How can I update a .yml file, ignoring preexisting Jinja syntax, using Python?》问题类似。我尝试按照该帖子给出的答案操作,但没有一个能适配我的YAML语法,我的YAML内容如下:

kind: Service
metadata:
  name: {{ .Chart.Name }}
  labels:
    app: {{ .Chart.Name }}
    service: {{ .Chart.Name }}
spec:
{{- if eq .Values.global.node.networkIpVersion "ipv6" }}
  ipFamily: IPv6
{{- end }}
  type: ClusterIP
  ports:
  - name: http2-8080
    protocol: TCP
    port: 8080
    targetPort: 8080
  selector:
    app: {{ .Chart.Name }}
---
apiVersion: v1
kind: Service
metadata:
  name: {{ .Chart.Name }}-traffic
  labels:
    app: {{ .Chart.Name }}
    service: {{ .Chart.Name }}-traffic
spec:
  ports:
  - name: http-2112
    port: {{ .Values.global.monitor.prometheusExporter.trafficListenPort }}
    protocol: TCP
    targetPort: 2112
  selector:
    app: {{ .Chart.Name }}

除此之外,我的YAML文件内还包含多段模板内容。我原本是要在Node.js环境下实现该需求,但没有找到对应语言的解决方案,因此转向Python寻求解法。

实现方案

核心思路是先将所有Jinja语法块替换为可被YAML解析的唯一占位符,修改完YAML结构后再反向替换回原Jinja内容,既保留原模板语法,又能正常操作YAML字段,推荐使用ruamel.yaml库,可完美保留原文件的缩进、换行、多文档结构。

依赖安装

pip install ruamel.yaml

示例代码

import re
from ruamel.yaml import YAML

# 匹配所有Jinja语法块的正则,支持{{}}、{{- -}}、{% %}等格式
jinja_pattern = re.compile(r'\{\{.*?\}\}|\{%.*?%\}|\{#.*?#\}', re.DOTALL)

def update_jinja_yaml(file_path, update_func):
    # 读取原文件内容
    with open(file_path, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # 替换Jinja块为唯一占位符,存储映射关系
    placeholder_map = {}
    counter = 0
    def replace_jinja(match):
        nonlocal counter
        placeholder = f"__JINJA_PLACEHOLDER_{counter}__"
        placeholder_map[placeholder] = match.group(0)
        counter += 1
        return placeholder
    
    processed_content = jinja_pattern.sub(replace_jinja, content)
    
    # 解析处理后的YAML,支持多文档
    yaml = YAML()
    yaml.preserve_quotes = True
    yaml.indent(mapping=2, sequence=4, offset=2)
    docs = list(yaml.load_all(processed_content))
    
    # 执行用户自定义的更新逻辑,比如修改端口、新增字段等
    update_func(docs)
    
    # 将修改后的YAML转成字符串
    from io import StringIO
    output_stream = StringIO()
    yaml.dump_all(docs, output_stream)
    modified_content = output_stream.getvalue()
    
    # 反向替换占位符为原Jinja内容
    for placeholder, jinja_content in placeholder_map.items():
        modified_content = modified_content.replace(placeholder, jinja_content)
    
    # 写回文件
    with open(file_path, 'w', encoding='utf-8') as f:
        f.write(modified_content)

# 示例:给第一个Service新增一个端口
def my_update_logic(docs):
    # docs[0]对应第一个Service文档,docs[1]对应第二个
    new_port = {
        "name": "http-9090",
        "protocol": "TCP",
        "port": 9090,
        "targetPort": 9090
    }
    docs[0]['spec']['ports'].append(new_port)

# 调用方法
if __name__ == "__main__":
    update_jinja_yaml("你的模板文件路径.yaml", my_update_logic)

方案说明

  • 正则支持匹配{{ 变量 }}、{% 控制语句 %}、{# 注释 #}三类Jinja语法,覆盖绝大多数模板场景
  • 保留原文件的所有格式、缩进、多文档分隔符,不会破坏原有结构
  • 自定义更新逻辑完全解耦,你可以根据自己的需求修改任意YAML字段

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 19:06:03