第58章 Template Engine
SATE(SAI Template Engine)中的 TemplateEngine 是模板系统的运行核心。
第57章已经定义了 Template 的组成:
Template
├── Object
├── Variable
├── Property
├── Method
├── Condition
├── Loop
└── Context
本章进一步建立 Template 从加载、解析、编译、缓存、注册到执行的完整运行机制。
核心流程:
Template Source
↓
TemplateLoader
↓
TemplateParser
↓
TemplateCompiler
↓
TemplateCache
↓
TemplateRegistry
↓
TemplateEngine
↓
Template Context
↓
Template Execution
↓
Rendered Output
1. TemplateEngine
1.1 TemplateEngine 定义
TemplateEngine 是 SATE 中负责组织和执行整个模板处理流程的核心引擎。
可以定义为:
TemplateEngine
=
Load
+
Parse
+
Compile
+
Cache
+
Registry
+
Execute
它不是单独负责解析模板,而是负责协调各个模板组件。
TemplateEngine
│
├── TemplateLoader
├── TemplateParser
├── TemplateCompiler
├── TemplateCache
├── TemplateRegistry
└── Template Executor
1.2 TemplateEngine 的职责
TemplateEngine 主要完成:
- 获取模板
- 加载模板
- 解析模板
- 编译模板
- 缓存编译结果
- 注册模板
- 创建 Template Context
- 执行模板
- 输出 Render Result
因此:
TemplateEngine
是一个模板运行协调器。
1.3 TemplateEngine 不负责什么
TemplateEngine 不应该负责:
认知
推理
决策
学习
知识形成
事实判断
行为决策
也就是说:
ReasoningEngine
→ 负责推理
Decision
→ 负责决策
Behavior
→ 负责行为
ActionExecutor
→ 负责行动
Expression
→ 负责表现
TemplateEngine
→ 负责模板执行
这样能够保持 SAI/ICAI 各模块职责清晰。
2. TemplateLoader
2.1 TemplateLoader 定义
TemplateLoader 负责获取模板源。
基本流程:
Template Name
↓
TemplateLoader
↓
Template Source
例如:
company.html
通过 Loader 获取:
<div>
<h1>{{Company.name}}</h1>
</div>
2.2 Template 来源
SATE 可以允许不同的模板来源:
File
String
Database
Memory
Package
Remote Source
但不同来源不应该改变 TemplateEngine 的核心执行流程。
例如:
File
↓
Loader
↓
Template Source
或者:
String
↓
Loader
↓
Template Source
最终都进入:
TemplateParser
2.3 TemplateLoader 基本结构
TemplateLoader
{
source
path
encoding
state
}
主要方法:
load()
exists()
getSource()
getPath()
validate()
例如:
TemplateLoader.load("company.html")
返回:
TemplateSource
{
name: "company.html",
source: "...",
state: "LOADED"
}
2.4 Loader 状态
可以定义:
NEW
LOADING
LOADED
NOT_FOUND
INVALID
ERROR
其中:
LOADED
才允许进入 Parser。
3. TemplateParser
3.1 TemplateParser 定义
TemplateParser 负责把模板源代码解析成 SATE 可以识别的模板结构。
Template Source
↓
TemplateParser
↓
Template Structure
例如:
<h1>{{Company.name}}</h1>
解析成:
Template
│
└── Element
├── Text
└── Variable
└── Company.name
3.2 Parser 的作用
Parser 不执行模板。
它只负责:
读取
识别
拆分
组织
验证
因此:
Parser ≠ Executor
3.3 Token
Parser 可以首先将模板拆成 Token。
例如:
<h1>{{Company.name}}</h1>
可以解析为:
TEXT "<h1>"
VARIABLE "Company.name"
TEXT "</h1>"
形成:
Template Source
↓
Tokenization
↓
Tokens
↓
Template Structure
3.4 Condition Token
例如:
{{if Product.state == "active"}}
Available
{{/if}}
可以形成:
IF
├── Condition
│ ├── Object: Product
│ ├── Property: state
│ ├── Operator: ==
│ └── Value: active
│
└── Body
└── TEXT: Available
3.5 Loop Token
例如:
{{foreach Products as Product}}
{{Product.name}}
{{/foreach}}
可以解析为:
FOREACH
├── Collection: Products
├── Variable: Product
└── Body
└── Variable: Product.name
4. TemplateCompiler
4.1 TemplateCompiler 定义
Parser 得到的是结构。
Compiler 将模板结构转换为更适合执行的内部结构。
Template Source
↓
Parser
↓
Template AST / Structure
↓
Compiler
↓
Compiled Template
这里的 Compiler 并不是把模板编译成机器代码。
它主要是:
把模板结构转换为 SATE 可快速执行的内部表示。
4.2 为什么需要 Compiler
如果每一次输出都重新解析:
Load
↓
Parse
↓
Resolve
↓
Execute
重复成本较高。
因此可以:
第一次
Template
↓
Parse
↓
Compile
↓
CompiledTemplate
之后:
Data
↓
CompiledTemplate
↓
Execute
4.3 CompiledTemplate
可以定义:
CompiledTemplate
{
id
name
nodes
variables
conditions
loops
methods
version
state
}
例如:
CompiledTemplate
{
name: "company",
nodes: [
TEXT,
VARIABLE,
TEXT,
CONDITION,
LOOP
],
state: "READY"
}
4.4 Compiler 的基本过程
Template Structure
↓
Node Analysis
↓
Variable Mapping
↓
Property Mapping
↓
Condition Mapping
↓
Loop Mapping
↓
Method Mapping
↓
CompiledTemplate
5. TemplateCache
5.1 TemplateCache 定义
TemplateCache 用于保存已经加载、解析或编译后的模板资源。
最常见的是缓存:
CompiledTemplate
流程:
Template
↓
Compile
↓
Cache
再次使用:
Template Name
↓
Cache
↓
CompiledTemplate
↓
Execute
5.2 Cache 的目的
主要目的:
减少重复加载
减少重复解析
减少重复编译
提高执行效率
例如第一次:
company.html
↓
Load
↓
Parse
↓
Compile
↓
Cache
第二次:
company.html
↓
Cache Hit
↓
CompiledTemplate
↓
Execute
5.3 Cache Hit / Miss
可以定义:
Cache Hit
→ 缓存存在且有效
Cache Miss
→ 缓存不存在或已经失效
执行:
Request
↓
Cache?
├── HIT → Execute
│
└── MISS
↓
Load
↓
Parse
↓
Compile
↓
Cache
↓
Execute
5.4 Cache 状态
EMPTY
VALID
EXPIRED
INVALID
DELETED
如果模板文件发生变化:
Old Cache
↓
INVALID
↓
Reload
↓
Parse
↓
Compile
↓
New Cache
因此缓存不能凌驾于模板源文件的真实性之上。
6. TemplateRegistry
6.1 TemplateRegistry 定义
TemplateRegistry 是 SATE 中用于登记和管理模板的注册表。
例如:
TemplateRegistry
{
company
product
product_list
error
status
}
它解决的问题是:
系统当前有哪些可用模板?
6.2 Registry 与 Cache 的区别
二者必须区分。
TemplateRegistry
→ 管理模板登记信息
TemplateCache
→ 保存模板运行缓存
例如:
Registry
{
product: "templates/product.html"
}
表示:
product 模板在哪里
而:
Cache
{
product: CompiledTemplate
}
表示:
product 模板已经编译好的运行结构
因此:
Registry ≠ Cache
6.3 Registry 基本结构
TemplateRegistry
{
templates
aliases
versions
states
}
例如:
templates
{
company: "company.html",
product: "product.html",
list: "product_list.html"
}
6.4 Registry 方法
可以提供:
register()
unregister()
exists()
get()
set()
list()
enable()
disable()
例如:
register(
"product",
"templates/product.html"
)
之后:
get("product")
即可获得模板登记信息。
7. Template 执行
现在将前面所有组件连接起来。
7.1 完整执行流程
Template Name
↓
TemplateRegistry
↓
TemplateLoader
↓
TemplateCache
↓
TemplateParser
↓
TemplateCompiler
↓
CompiledTemplate
↓
TemplateContext
↓
TemplateExecutor
↓
Rendered Output
注意:
Cache
应该在合理位置进行检查。
完整逻辑:
Request Template
↓
Registry
↓
Cache?
┌────┴────┐
HIT MISS
↓ ↓
Compile Loader
↓ ↓
Execute Parser
↓
Compiler
↓
Cache
↓
Execute
7.2 创建 Context
模板执行之前,需要建立:
TemplateContext
例如:
TemplateContext
{
Company,
Products,
current_date
}
然后:
CompiledTemplate
+
TemplateContext
进入执行阶段。
7.3 Variable Resolution
例如:
{{Company.name}}
执行:
Context
↓
Company
↓
name
↓
Value
↓
Render
7.4 Condition Execution
例如:
{{if Company.state == "active"}}
Active
{{/if}}
执行:
Company.state
↓
"active"
↓
Condition
↓
TRUE
↓
Render Body
7.5 Loop Execution
例如:
{{foreach Products as Product}}
{{Product.name}}
{{/foreach}}
执行:
Products
↓
Collection
↓
Loop
├── Product A → Render
├── Product B → Render
└── Product C → Render
8. 完整模板运行
下面建立一个完整的 SATE Template Engine 运行实例。
8.1 原始数据
系统已经拥有:
Company
{
name: "Company A",
city: "Shenzhen",
state: "active"
}
以及:
Products
[
{
name: "Product A",
price: 29.90,
state: "active"
},
{
name: "Product B",
price: 39.90,
state: "inactive"
}
]
这些数据已经存在。
TemplateEngine 不负责产生这些数据。
8.2 Template
<div class="company">
<h1>{{Company.name}}</h1>
<p>City: {{Company.city}}</p>
{{if Company.state == "active"}}
<p>Status: Active</p>
{{else}}
<p>Status: Inactive</p>
{{/if}}
<ul>
{{foreach Products as Product}}
<li>
<strong>{{Product.name}}</strong>
<span>{{Product.price}}</span>
{{if Product.state == "active"}}
<span>Available</span>
{{else}}
<span>Unavailable</span>
{{/if}}
</li>
{{/foreach}}
</ul>
</div>
8.3 Registry
首先注册:
TemplateRegistry
{
company:
"templates/company.html"
}
执行:
get("company")
得到:
templates/company.html
8.4 Loader
Loader 加载:
templates/company.html
得到:
TemplateSource
{
name: "company",
state: "LOADED"
}
8.5 Cache 检查
第一次运行:
Cache
↓
MISS
因此继续:
Parser
8.6 Parser
Parser 得到:
Template
│
├── Text
├── Variable
│ └── Company.name
│
├── Variable
│ └── Company.city
│
├── Condition
│ └── Company.state == active
│
└── Loop
└── Products
└── Product
├── name
├── price
└── state condition
8.7 Compiler
Compiler 将其转换:
CompiledTemplate
{
nodes: [
TEXT,
VARIABLE,
TEXT,
VARIABLE,
CONDITION,
LOOP
],
state: "READY"
}
然后:
CompiledTemplate
↓
TemplateCache
8.8 Context
建立:
TemplateContext
{
Company,
Products
}
进入执行:
CompiledTemplate
+
TemplateContext
8.9 TemplateEngine 执行
第一步:
{{Company.name}}
得到:
Company A
第二步:
{{Company.city}}
得到:
Shenzhen
第三步:
Company.state == active
得到:
TRUE
因此表现:
<p>Status: Active</p>
8.10 Loop 执行
Products 有两个对象:
Product A
Product B
第一次:
Product = Product A
得到:
Product A
29.90
Available
第二次:
Product = Product B
得到:
Product B
39.90
Unavailable
8.11 最终 Render Result
最终输出:
<div class="company">
<h1>Company A</h1>
<p>City: Shenzhen</p>
<p>Status: Active</p>
<ul>
<li>
<strong>Product A</strong>
<span>29.9</span>
<span>Available</span>
</li>
<li>
<strong>Product B</strong>
<span>39.9</span>
<span>Unavailable</span>
</li>
</ul>
</div>
TemplateEngine 完整架构
至此,SATE 的模板运行体系可以形成:
SATE
│
TemplateEngine
│
┌────────────┼────────────┐
│ │ │
TemplateLoader Parser Registry
│ │ │
│ Template AST │
│ │ │
│ Compiler │
│ │ │
└────────────┼────────────┘
│
TemplateCache
│
CompiledTemplate
│
TemplateContext
│
Template Execute
│
Render
│
Expression Result
│
Output
TemplateEngine 与 SATE 的关系
可以进一步明确:
SATE
│
├── Template
│
├── TemplateEngine
│
├── TemplateLoader
│
├── TemplateParser
│
├── TemplateCompiler
│
├── TemplateCache
│
├── TemplateRegistry
│
├── TemplateContext
│
└── Renderer
其中:
Template
→ 定义表现结构
TemplateLoader
→ 获取模板
TemplateParser
→ 解析模板
TemplateCompiler
→ 建立可执行模板结构
TemplateCache
→ 保存可复用模板结构
TemplateRegistry
→ 管理模板登记
TemplateContext
→ 提供执行环境
TemplateEngine
→ 组织整个运行过程
Renderer
→ 形成最终表现结果
本章核心模型
Template
↓
Registry
↓
Loader
↓
Cache
↓
Parser
↓
Compiler
↓
CompiledTemplate
↓
Context
↓
Engine
↓
Execute
↓
Render
↓
Output
其中第一次运行通常是:
Load
↓
Parse
↓
Compile
↓
Cache
↓
Execute
后续运行可以直接:
Registry
↓
Cache
↓
CompiledTemplate
↓
Context
↓
Execute
最终定义:
TemplateEngine 是 SATE 中负责组织 TemplateLoader、TemplateParser、TemplateCompiler、TemplateCache、TemplateRegistry、TemplateContext 与模板执行过程的核心运行引擎,用于将模板与已有结构化数据按照确定性的模板规则转换为表现结果。
最重要的边界仍然是:
Template = 定义表现结构
TemplateEngine = 执行表现结构
Expression = 表达结果
Output = 外部表现
而不是:
TemplateEngine → 认知
TemplateEngine → 推理
TemplateEngine → 决策
TemplateEngine → 学习
这样,SATE 可以作为 ICAI Expression → Template → Output 这一层的独立、确定性表现引擎。