第59章 SATE 模板语法
SATE 模板语法是 Template 与 TemplateEngine 之间的规则表达层。
第57章定义了 Template 的基本组成,第58章建立了 TemplateEngine 的运行流程。本章进一步规定:
模板如何书写,以及 TemplateParser 如何识别这些语法。
SATE 模板语法的核心原则是:
模板语法
↓
Parser 识别
↓
结构化节点
↓
Compiler
↓
TemplateEngine
↓
Render
模板语法本身不负责认知、推理、决策和学习。
1. 变量
变量是 SATE 最基础的模板语法。
基本形式:
{{name}}
例如:
<h1>{{title}}</h1>
<p>{{content}}</p>
数据:
{
"title": "WSaiOS",
"content": "SAI Template Engine"
}
执行结果:
<h1>WSaiOS</h1>
<p>SAI Template Engine</p>
1.1 对象变量
可以直接引用对象:
{{Company}}
也可以引用对象属性:
{{Company.name}}
形成:
Variable
↓
Object
↓
Property
↓
Value
1.2 变量路径
支持层级路径:
{{Company.address.city}}
解析:
Company
↓
address
↓
city
↓
Value
1.3 变量不存在
如果变量不存在:
{{Company.phone}}
SATE 不应该自动生成数据。
根据模板配置,可以返回:
EMPTY
MISSING
UNKNOWN
或者使用默认值:
{{Company.phone | default:"N/A"}}
结果:
N/A
2. 属性
属性语法用于访问对象属性。
基本形式:
{{Object.Property}}
例如:
{{Product.name}}
{{Product.price}}
{{Product.state}}
数据:
Product
{
name: "Product A",
price: 29.90,
state: "active"
}
模板:
<h1>{{Product.name}}</h1>
<p>{{Product.price}}</p>
2.1 多级属性
{{Company.contact.email}}
解析:
Company
↓
contact
↓
email
2.2 属性与变量的区别
{{name}}
表示当前 Context 中的变量。
而:
{{Product.name}}
表示:
Product 对象
↓
name 属性
因此:
Variable = 数据引用
Property = 对象数据访问
3. 方法
SATE 可以允许模板调用经过授权的方法。
基本形式:
{{Object.method()}}
例如:
{{Product.getName()}}
或者:
{{Product.formatPrice()}}
数据:
Product.price = 29.9
方法:
formatPrice()
返回:
29.90
模板:
<p>{{Product.formatPrice()}}</p>
3.1 带参数方法
可以支持:
{{Product.formatPrice(2)}}
表示:
formatPrice(2)
但是方法参数必须经过解析和验证。
3.2 方法权限
模板不能任意调用系统方法。
应当采用:
Template
↓
Method Resolver
↓
Allowed Method
↓
Execute
例如允许:
getName()
format()
display()
escape()
而不是允许模板执行任意系统命令。
3.3 方法与属性
{{Product.name}}
是属性访问。
{{Product.getName()}}
是方法调用。
因此:
Property → Read
Method → Operation
4. 条件
条件语法控制某一段模板是否表现。
基本形式:
{{if condition}}
...
{{/if}}
例如:
{{if Product.state == "active"}}
<p>Available</p>
{{/if}}
4.1 IF / ELSE
{{if Product.stock > 0}}
<p>In Stock</p>
{{else}}
<p>Out of Stock</p>
{{/if}}
执行:
Product.stock > 0
↓
Condition
┌───┴───┐
TRUE FALSE
↓ ↓
In Stock Out of Stock
4.2 多条件
可以支持:
AND
OR
NOT
例如:
{{if Product.state == "active" AND Product.stock > 0}}
<p>Available</p>
{{/if}}
解析为:
AND
├── Product.state == active
└── Product.stock > 0
4.3 条件状态
模板条件可以产生:
TRUE
FALSE
UNKNOWN
CONFLICT
例如:
Product.stock
不存在时:
Product.stock > 0
不能直接认为:
FALSE
更合理的是:
UNKNOWN
具体表现由 SATE 的条件策略决定。
5. 循环
循环用于重复表现集合数据。
基本形式:
{{foreach Items as Item}}
...
{{/foreach}}
例如:
<ul>
{{foreach Products as Product}}
<li>
{{Product.name}}
</li>
{{/foreach}}
</ul>
5.1 Loop Context
每次循环都会产生当前对象:
Products
│
├── Product A
├── Product B
└── Product C
执行:
Loop Context
├── Product = Product A
├── Product = Product B
└── Product = Product C
因此:
{{Product.name}}
在每一次循环中对应当前 Product。
5.2 Index
可以提供循环索引:
{{foreach Products as Product}}
{{index}}. {{Product.name}}
{{/foreach}}
结果:
1. Product A
2. Product B
3. Product C
Index 属于 Loop Context,而不是 Product 本身。
5.3 空集合
如果:
Products = []
则:
{{foreach Products as Product}}
...
{{/foreach}}
循环次数为:
0
可以配合条件:
{{if Products}}
{{foreach Products as Product}}
<p>{{Product.name}}</p>
{{/foreach}}
{{else}}
<p>No Products</p>
{{/if}}
6. Include
Include 用于把另一个模板包含到当前模板。
基本形式:
{{include "header.html"}}
例如:
{{include "header.html"}}
<main>
<h1>{{title}}</h1>
</main>
{{include "footer.html"}}
结构:
main.html
│
├── header.html
├── main content
└── footer.html
6.1 Include 的作用
Include 主要用于模板复用:
Header
Footer
Navigation
Sidebar
Common Block
例如:
templates/
├── header.html
├── footer.html
├── navigation.html
└── product.html
product.html:
{{include "header.html"}}
<h1>{{Product.name}}</h1>
{{include "footer.html"}}
6.2 Include Context
Include 可以继承当前 Context:
Main Context
↓
Include
↓
Header Template
例如:
Context
{
Company,
User,
Product
}
Header 可以访问:
{{Company.name}}
也可以设计独立 Context:
{{include "header.html" with Header}}
形成:
Main Context
↓
Header Context
具体采用哪一种方式,由 SATE 语法规范确定。
6.3 Include 防止无限递归
例如:
A.html
↓
include B.html
B.html
↓
include A.html
形成:
A → B → A → B → ...
因此 TemplateEngine 应该记录 Include 路径:
Include Stack
[
A.html,
B.html
]
如果发现:
A.html
再次进入当前栈,则产生:
INCLUDE_RECURSION
而不是无限执行。
7. Extend
Extend 用于建立模板继承关系。
例如:
{{extend "layout.html"}}
表示当前模板继承:
layout.html
结构:
layout.html
↑
│ extend
│
product.html
7.1 Layout Template
基础模板:
<html>
<head>
{{block "head"}}
{{/block}}
</head>
<body>
{{block "content"}}
{{/block}}
</body>
</html>
子模板:
{{extend "layout.html"}}
{{block "content"}}
<h1>{{Product.name}}</h1>
{{/block}}
最终:
layout
│
├── head block
│
└── content block
↓
Product Content
7.2 Extend 与 Include 的区别
两者不能混淆:
Include
→ 把一个模板放进当前模板
Extend
→ 当前模板继承基础模板结构
例如:
Include:
A + B
而:
Extend:
Base
↑
Child
8. Block
Block 是 Extend 体系中的模板占位区域。
基础模板:
{{block "content"}}
Default Content
{{/block}}
子模板:
{{extend "layout.html"}}
{{block "content"}}
<h1>Product A</h1>
{{/block}}
执行时:
Base Block
↓
Find Child Block
↓
Replace / Override
↓
Render
8.1 Block 的结构
可以抽象:
Block
{
name
content
parent
state
}
例如:
Block
{
name: "content",
content: "...",
state: "ACTIVE"
}
8.2 Block 默认内容
如果子模板没有覆盖:
{{block "content"}}
Default Content
{{/block}}
则使用:
Default Content
这样基础模板可以独立运行。
8.3 Block 与 Include
Include
→ 引入模板
Block
→ 定义可替换区域
通常:
Extend + Block
组成模板继承机制。
9. 自定义标签
SATE 可以定义自定义标签。
例如:
{{product Product}}
或者:
{{display Product.name}}
这些标签不是 HTML 标签,而是 SATE Template Tag。
9.1 自定义标签结构
可以定义:
CustomTag
{
name
parameters
body
handler
state
}
例如:
CustomTag
{
name: "product",
parameters: ["Product"]
}
Parser 识别:
{{product Product}}
然后:
Tag Resolver
↓
CustomTag Handler
↓
Result
↓
Render
9.2 自定义标签示例
定义:
{{price Product.price}}
数据:
Product.price = 29.9
标签处理器:
price()
得到:
29.90
模板:
<p>{{price Product.price}}</p>
结果:
<p>29.90</p>
9.3 自定义标签的边界
自定义标签不能成为隐藏的认知引擎。
它应该主要用于:
格式处理
表现处理
数据映射
输出组件
而不是:
推理
决策
学习
知识生成
否则 Template 层和 ICAI 核心认知层会发生职责混乱。
10. 模板语法解析
TemplateParser 是整个语法体系的入口。
它需要把:
Template Source
转换成:
Template Nodes
10.1 Lexer / Tokenizer
第一步可以进行 Token 分析。
例如:
<h1>{{Product.name}}</h1>
解析:
TEXT
VARIABLE_START
PATH
VARIABLE_END
TEXT
形成:
[
TEXT("<h1>"),
VARIABLE("Product.name"),
TEXT("</h1>")
]
10.2 Block Token
例如:
{{if Product.state == "active"}}
Available
{{/if}}
解析:
IF_START
CONDITION
TEXT
IF_END
然后形成结构:
IF
├── Condition
└── Body
└── Text
10.3 Loop Token
{{foreach Products as Product}}
{{Product.name}}
{{/foreach}}
解析:
FOREACH_START
COLLECTION
VARIABLE
TEXT / VARIABLE
FOREACH_END
最终:
FOREACH
├── Products
├── Product
└── Body
└── Product.name
10.4 Include Token
{{include "header.html"}}
解析:
INCLUDE
└── "header.html"
10.5 Extend Token
{{extend "layout.html"}}
解析:
EXTEND
└── "layout.html"
10.6 Block Token
{{block "content"}}
...
{{/block}}
解析:
BLOCK
├── name: content
└── body
10.7 Template AST
所有语法最终可以组织成模板结构树。
例如:
{{extend "layout.html"}}
{{block "content"}}
<h1>{{Company.name}}</h1>
{{if Company.state == "active"}}
{{foreach Products as Product}}
<p>{{Product.name}}</p>
{{/foreach}}
{{/if}}
{{/block}}
解析为:
Template
│
├── Extend
│ └── layout.html
│
└── Block
└── content
│
├── Text
│
├── Variable
│ └── Company.name
│
└── Condition
│
└── Loop
│
├── Collection
│ └── Products
│
└── Variable
└── Product.name
这就是 SATE Template 的内部结构。
10.8 语法解析完整流程
Template Source
↓
Tokenizer
↓
Token
↓
Parser
↓
Syntax Validation
↓
Template Structure
↓
AST
↓
Compiler
↓
Compiled Template
SATE 模板语法总表
| 语法 | 作用 |
|---|---|
{{name}} |
变量 |
{{Object.property}} |
属性 |
{{Object.method()}} |
方法 |
{{if ...}} |
条件 |
{{else}} |
条件分支 |
{{/if}} |
条件结束 |
{{foreach ...}} |
循环 |
{{/foreach}} |
循环结束 |
{{include ...}} |
模板包含 |
{{extend ...}} |
模板继承 |
{{block ...}} |
模板区块 |
{{/block}} |
区块结束 |
{{custom ...}} |
自定义标签 |
SATE Template Syntax 总体结构
SATE Template Syntax
│
├── Variable
│
├── Property
│
├── Method
│
├── Condition
│ ├── IF
│ ├── ELSE
│ └── Operators
│
├── Loop
│ └── FOREACH
│
├── Include
│
├── Extend
│
├── Block
│
└── Custom Tag
最终进入:
Template Syntax
↓
Tokenizer
↓
Parser
↓
Template Structure
↓
Compiler
↓
TemplateEngine
↓
Context + Data
↓
Render
↓
Expression Output
本章核心定义
SATE 模板语法是 SATE Template 用于描述变量访问、对象属性、方法调用、条件表现、循环表现、模板包含、模板继承、区块覆盖及自定义表现标签的一组确定性语法规则;TemplateParser 将这些语法解析为结构化模板节点,再由 TemplateCompiler 和 TemplateEngine 执行。
核心边界:
Template Syntax
↓
描述“如何表现”
↓
TemplateParser
↓
TemplateCompiler
↓
TemplateEngine
↓
Render
而不是:
Template Syntax
↓
认知
推理
决策
学习
因此,SATE 的模板语法可以保持为一个独立、可解析、可编译、可执行、确定性的表现语法体系。