apppublic/aidocs/myTE.md
2025-10-05 11:23:33 +08:00

345 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 模板引擎技术文档
## 简介
`MyTemplateEngine` 是一个基于 [Jinja2](https://jinja.palletsprojects.com/) 的轻量级模板渲染引擎支持文件和字符串模板的渲染、变量注入、JSON 数据加载以及自定义全局函数。该模块封装了常用的文件路径处理、类型转换、数据访问等功能,适用于配置生成、报告输出、代码模板等场景。
---
## 功能特性
- ✅ 支持从字符串或文件加载模板
- ✅ 支持多路径模板搜索(通过 `pathList`
- ✅ 内置常用工具函数(如 `json`, `hasattr`, 类型转换等)
- ✅ 提供便捷的 JSON 文件与模板结合渲染功能
- ✅ 自动处理跨平台路径分隔符
- ✅ 可扩展的全局变量/函数注入机制
- ✅ 支持 UTF-8 编码输入输出(可配置)
---
## 安装依赖
```bash
pip install jinja2 ujson apppublic
```
> 注:`appPublic.argsConvert` 和 `appPublic.dictObject` 来自第三方包 `apppublic`,需确保已安装。
---
## 模块导入说明
```python
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` 如果 `obj``None`,否则 `False`
---
### `string_template_render(tmp_string: str, data: dict) -> str`
使用字典数据渲染字符串模板。
#### 参数:
- `tmp_string`: Jinja2 风格的模板字符串
- `data`: 渲染所需的数据字典
#### 示例:
```python
result = string_template_render("Hello {{ name }}!", {"name": "Alice"})
# 输出: Hello Alice!
```
---
## 类:`MyTemplateEngine`
主模板引擎类,封装了完整的模板解析与渲染能力。
### 构造函数:`__init__(pathList, file_coding='utf-8', out_coding='utf-8', env={})`
初始化模板引擎实例。
#### 参数:
| 参数名 | 类型 | 说明 |
|---------------|------------------|------|
| `pathList` | `str``list` | 模板文件搜索路径列表(支持单个路径或路径列表) |
| `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 | 获取文件扩展名 |
#### 示例:
```python
te = MyTemplateEngine(['/templates', '/shared'], file_coding='utf-8')
```
---
### 方法:`get_template_variables(tmpl: str) -> list[str]`
分析模板字符串中所有未声明但使用的变量名。
#### 参数:
- `tmpl`: Jinja2 模板字符串
#### 返回值:
- 所有在模板中引用但未定义的变量名列表(可用于调试或预检)
#### 示例:
```python
vars = te.get_template_variables("Hello {{ user.name }}! You have {{ count }} messages.")
# 返回: ['user', 'count']
```
---
### 方法:`set(k: str, v: Any)`
向模板上下文注入全局变量或函数。
#### 参数:
- `k`: 变量名(字符串)
- `v`: 值或可调用对象
> ⚠️ 注意:此操作会影响后续所有模板渲染。
#### 示例:
```python
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()` 访问原始数据结构。
#### 示例模板:
```jinja2
User: {{ global().user.name }}
Total: {{ len(global().items) }}
```
#### 使用示例:
```python
output = te.renders("Hello {{ name }}!", {"name": "Bob"})
```
---
### 方法:`render(tmplfile: str, data: dict) -> str`
渲染指定路径的模板文件。
#### 参数:
- `tmplfile`: 模板文件相对或绝对路径(将在 `pathList` 中查找)
- `data`: 渲染数据字典
#### 示例:
```python
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)`
#### 示例:
```python
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. 返回文件路径
#### 示例:
```python
temp_path = tmpTml('template.txt', {'name': 'Test'})
print(f"Generated at: {temp_path}")
```
---
## 命令行使用
当直接运行此脚本时,支持命令行调用:
```bash
python template_engine.py <template_file> <json_data_file>
```
#### 示例:
```bash
python template_engine.py hello.tmpl.json data.json
```
程序会:
1. 读取模板文件
2. 加载 JSON 数据
3. 渲染并输出结果到标准输出
> 若参数不足,打印用法提示并退出。
---
## 模板语法示例Jinja2
```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()` 方法添加更多工具函数,例如:
```python
te.set('upper', str.upper)
te.set('today', lambda: datetime.today().strftime('%Y-%m-%d'))
```
也可集成 `DictObject` 实现更灵活的数据访问。
---
## 版权与许可
© 2025 Your Company. 开源项目,请保留原作者信息。
使用遵循 MIT License除非另有声明