2025-10-05 11:23:33 +08:00

8.2 KiB
Raw Permalink Blame History

模板引擎技术文档

简介

MyTemplateEngine 是一个基于 Jinja2 的轻量级模板渲染引擎支持文件和字符串模板的渲染、变量注入、JSON 数据加载以及自定义全局函数。该模块封装了常用的文件路径处理、类型转换、数据访问等功能,适用于配置生成、报告输出、代码模板等场景。


功能特性

  • 支持从字符串或文件加载模板
  • 支持多路径模板搜索(通过 pathList
  • 内置常用工具函数(如 json, hasattr, 类型转换等)
  • 提供便捷的 JSON 文件与模板结合渲染功能
  • 自动处理跨平台路径分隔符
  • 可扩展的全局变量/函数注入机制
  • 支持 UTF-8 编码输入输出(可配置)

安装依赖

pip install jinja2 ujson apppublic

注:appPublic.argsConvertappPublic.dictObject 来自第三方包 apppublic,需确保已安装。


模块导入说明

import os
import sys
try:
    import ujson as json  # 更快的 JSON 解析器
except ImportError:
    import json           # 标准库回退
from jinja2 import Environment, FileSystemLoader, BaseLoader, meta
import codecs
from appPublic.argsConvert import ArgsConvert
from appPublic.dictObject import DictObject

公共函数

isNone(obj) -> bool

判断对象是否为 None

参数:

  • obj: 任意对象

返回值:

  • True 如果 objNone,否则 False

string_template_render(tmp_string: str, data: dict) -> str

使用字典数据渲染字符串模板。

参数:

  • tmp_string: Jinja2 风格的模板字符串
  • data: 渲染所需的数据字典

示例:

result = string_template_render("Hello {{ name }}!", {"name": "Alice"})
# 输出: Hello Alice!

类:MyTemplateEngine

主模板引擎类,封装了完整的模板解析与渲染能力。

构造函数:__init__(pathList, file_coding='utf-8', out_coding='utf-8', env={})

初始化模板引擎实例。

参数:

参数名 类型 说明
pathList strlist 模板文件搜索路径列表(支持单个路径或路径列表)
file_coding str 模板文件读取编码,默认 'utf-8'
out_coding str 输出编码(目前主要用于内部一致性,实际返回为字符串)
env dict 用户自定义注入到模板中的全局变量或函数

初始化行为:

  1. 创建 FileSystemLoader 加载器,用于从指定路径加载模板。
  2. 初始化 Environment 并注册内置函数和工具。
  3. 向 Jinja2 全局命名空间 (globals) 注入以下内容:
名称 类型 用途
json module 提供 json.dumps/json.loads
hasattr built-in 判断对象是否有某属性
int, float, str, type, len built-in 基础类型与操作
isNone function 判断是否为 None
render method 调用当前引擎渲染模板文件
renders method 渲染模板字符串
ArgsConvert class 参数转换工具类
renderJsonFile method 快捷方法:用 JSON 文件数据渲染模板
ospath(x) lambda 统一路径分隔符(适应 Windows/Linux
basename(x) lambda 获取路径中的文件名部分
basenameWithoutExt(x) lambda 获取无扩展名的文件名
extname(x) lambda 获取文件扩展名

示例:

te = MyTemplateEngine(['/templates', '/shared'], file_coding='utf-8')

方法:get_template_variables(tmpl: str) -> list[str]

分析模板字符串中所有未声明但使用的变量名。

参数:

  • tmpl: Jinja2 模板字符串

返回值:

  • 所有在模板中引用但未定义的变量名列表(可用于调试或预检)

示例:

vars = te.get_template_variables("Hello {{ user.name }}! You have {{ count }} messages.")
# 返回: ['user', 'count']

方法:set(k: str, v: Any)

向模板上下文注入全局变量或函数。

参数:

  • k: 变量名(字符串)
  • v: 值或可调用对象

⚠️ 注意:此操作会影响后续所有模板渲染。

示例:

te.set('site_name', 'MySite')
te.set('now', lambda: datetime.now())

方法:_render(template: Template, data: dict) -> str

内部方法:执行模板渲染。

参数:

  • template: 已加载的 Jinja2 Template 对象
  • data: 数据字典

返回值:

  • 渲染后的字符串

方法:renders(tmplstring: str, data: dict) -> str

渲染模板字符串。

参数:

  • tmplstring: Jinja2 模板字符串
  • data: 渲染数据

特性:

  • 将传入的 data 包装成 global() 函数注入模板,允许在模板中通过 global() 访问原始数据结构。

示例模板:

User: {{ global().user.name }}
Total: {{ len(global().items) }}

使用示例:

output = te.renders("Hello {{ name }}!", {"name": "Bob"})

方法:render(tmplfile: str, data: dict) -> str

渲染指定路径的模板文件。

参数:

  • tmplfile: 模板文件相对或绝对路径(将在 pathList 中查找)
  • data: 渲染数据字典

示例:

with open('data.json') as f:
    data = json.load(f)
result = te.render('email_template.html', data)

方法:renderJsonFile(tmplfile: str, jsonfile: str) -> str

快捷方法:使用 JSON 文件中的数据渲染模板文件。

参数:

  • tmplfile: 模板文件路径
  • jsonfile: JSON 数据文件路径

行为:

  1. 读取并解析 jsonfile
  2. 使用其内容作为上下文调用 render(tmplfile, data)

示例:

output = te.renderJsonFile('report.html', 'data.json')

辅助函数:tmpTml(f: str, ns: dict) -> str

将模板文件渲染后保存至 /tmp/ 目录,并返回生成文件的路径。

参数:

  • f: 模板文件路径
  • ns: 数据上下文字典

返回值:

  • 生成的临时文件完整路径(例如 /tmp/report.html

流程:

  1. 创建 MyTemplateEngine 实例,搜索路径为当前目录 .
  2. 读取模板内容
  3. 渲染模板
  4. 写入 /tmp/<原文件名>
  5. 返回文件路径

示例:

temp_path = tmpTml('template.txt', {'name': 'Test'})
print(f"Generated at: {temp_path}")

命令行使用

当直接运行此脚本时,支持命令行调用:

python template_engine.py <template_file> <json_data_file>

示例:

python template_engine.py hello.tmpl.json data.json

程序会:

  1. 读取模板文件
  2. 加载 JSON 数据
  3. 渲染并输出结果到标准输出

若参数不足,打印用法提示并退出。


模板语法示例Jinja2

<!DOCTYPE html>
<html>
<head><title>{{ title }}</title></head>
<body>
  <h1>Welcome, {{ user.name }}!</h1>
  <p>You have {{ len(messages) }} messages.</p>

  {% if not isNone(subtitle) %}
    <h2>{{ subtitle }}</h2>
  {% endif %}

  <p>File: {{ basenameWithoutExt(global().input_file) }} (Ext: {{ extname(global().input_file) }})</p>
</body>
</html>

编码说明

  • 所有文件读写均使用 codecs.open(..., encoding='utf-8')
  • 默认编码可由构造函数设置
  • 推荐统一使用 UTF-8 编码避免乱码问题

错误处理建议

异常类型 建议措施
TemplateNotFound 检查 pathList 是否包含目标模板路径
UnicodeDecodeError 确保文件真实编码与 file_coding 一致
JSONDecodeError 验证 JSON 文件格式正确
UndefinedError 使用 get_template_variables() 检查缺失变量

扩展建议

可通过 env 参数或 set() 方法添加更多工具函数,例如:

te.set('upper', str.upper)
te.set('today', lambda: datetime.today().strftime('%Y-%m-%d'))

也可集成 DictObject 实现更灵活的数据访问。


版权与许可

© 2025 Your Company. 开源项目,请保留原作者信息。

使用遵循 MIT License除非另有声明