XTL 求值模型
本简体中文版本仅供阅读辅助。规范的正典是英文原版,如有规范性解释差异以英文为准。
本文档定义 XTL 实现如何读入输入并产出输出。
输入与输出(Inputs and Outputs)
一次 XTL 转换接受:
template.xlsx
data.xlsx
并产出一个或多个 .xlsx 输出 文件。
模板工作簿定义输出工作簿的形态、模板表达式、分组规则、指令与配置。源工作簿提供表格数据。
保留工作表(Reserved Sheets)
xl3 定义了四个保留的工作表名。任何名称匹配双下划线包裹模式 __<name>__ 的工作表都保留供引擎使用。作者不得(MUST NOT)创建这种形态的工作表;其余一切都属于模板内容。
| 工作表 | 用途 |
|---|---|
__config__ | 单一配置对象 —— 引擎元数据 + 作者自定义值 |
__inputs__ | 运行时输入声明(集合;见 输入) |
__sources__ | 命名外部数据源声明(集合;见 外部数据源,依 ADR-0012) |
__lists__ | 作者自定义的成员列表(集合;见 列表工作表) |
从单元格表达式引用保留工作表内容时,使用 Excel 结构化引用形式 __sheet__[key] —— 与未来某个 ADR 中用于多源列的形式相同。旧式 _<name> 引用语法在本版本中已淘汰。
模板配置(Template Configuration)
名为 __config__ 的隐藏工作表可以(MAY)提供元数据与作者自定义值。A 列存放键,B 列存放值。
| 键 | 含义 | 示例 |
|---|---|---|
name | 模板显示名 | Order summary |
description | 自由文本 | Monthly order summary |
source_sheet | 源工作表名,或以 * 结尾的前缀模式 | Orders、Data_* |
source_table | 源表选择器。所选范围中的第一行包含列名;下方为数据行。 | 1、A1:D、B5:H200 |
output_file_pattern | 输出文件名模板 | {{ __config__[customer] }}_report.xlsx |
match_pattern | 批量匹配模式 | Orders* |
| 其他任意键 | 作者自定义值 | title = Q2 Sales |
source_table 是唯一的源表选择器。
作者自定义值使用上述系统表之外的任意键。它们通过 {{ __config__[key] }} 从单元格引用。例如 title = Q2 Sales 这一行可通过 {{ __config__[title] }} 引用。作者不得(MUST NOT)将系统键名重新用作作者自定义值。
依 ADR-0056,无论 key 是系统槽位还是作者自定义槽位,__config__[key] 的读取形式都解析为该单元格的值。{{ __config__[name] }}、{{ __config__[output_file_pattern] }} 等都是合法读取。写入侧的限制(作者不能以系统键名声 明一行)保持不变。读取未知键会抛出 xl3/expression/unknown-name。
需要每次运行取值的模板改用 __inputs__ 工作表(见 输入)。
外部数据源(External Data Sources)
模板可以(MAY)通过提供保留工作表 __sources__ 来声明默认源之外的具名数据源。第 1 行是表头;之后每一行声明一个源。
| 列 | 必需 | 含义 |
|---|---|---|
name | 是 | 源名。仅允许字母、数字与下划线。不得(MUST NOT)以 __ 开头,也不得(MUST NOT)为 default(保留给隐式源)。 |
sheet | 是 | 数据工作簿中的源工作表名,或以 * 结尾的前缀模式。 |
table | 否 | 该工作表的源表选择器,默认为 1。语法与 __config__ 中的 source_table 相同。 |
description | 否 | 自由文本备注。 |
实现必须(MUST)按表头文本(大小写不敏感)识别列。
隐式的 default 源 —— 通过 __config__ 中的 source_sheet 与 source_table 行声明 —— 始终命名为 default。它不能在 __sources__ 中被重新声明。
单元格引用(Cell references)
[Column] 继续表示"当前活动源当前行的列"。Source[Column] 是命名源的结构化引用形式:
{{ [Account] }} 活动源的当前行
{{ Customers[Account] }} Customers 的当前行(仅当其为活动源时)
{{ SUM(Renewals[Amount]) }} 对 Renewals 完整行集的聚合
行级 Source[Column] 只有当 Source 是所在数据块的活动源时才有效。在聚合函数内部,Source[Column] 始终对 Source 的完整行集进行操作,与活动数据块无关。
@source 指令
数据块可以(MAY)将其迭代范围限定到某个命名源:
{{ @source Customers }}
{{ @filter [Region] = "Seoul" }}
{{ [Account] }}
{{ [Region] }}
上述数据块默认按垂直方向展开 —— 每个源行渲染一行 —— 不需要显式的 @repeat 指令(见 指令)。
未提供 @source 时,活动源为 default。@source 必须(MUST)出现在同一数据块的 @filter/@sort/@top 指令之前(它决定了这些指令操作的行集)。
引用未声明的源 —— 通过 @source <Unknown> 或 Unknown[Column] —— 是错误。
@join 指令
数据块可以(MAY)在 @source 之后立即添加一个 @join 指令,将每一行主源与第二个源的某一行配对:
{{ @source Renewals }}
{{ @join Customers on Customers[Account] = Renewals[Account] }}
{{ [Account] }} | {{ Customers[Name] }} | {{ [Amount] }}
对于每一主源行,引擎会找到第一条匹配的被连接行(依 比较算法),并渲染该配对。"第一"由被连接源的自然行序定义 —— 在其 source_table 范围内自上而下。这是规范性的:当多条被连接行的连接键相等时,两种实现必须(MUST)选取同一行进行配对。
如果未找到匹配,则主源行被丢弃(内连接语义)。
在块内部,[Column] 与 <PrimarySource>[Column] 解析到主源行;<JoinedSource>[Column] 解析到配对的被连接行。在行级引用其他源仍属于错误。
XTL 0.1 范围之外:多个 @join 指令、左连接语义以及多行匹配。
输入(Inputs)
模板可以(MAY)通过提供名为 __inputs__ 的保留工作表来声明运行时输入。第一行是表头;之后每一行声明一个输入。
| 列 | 必需 | 含义 |
|---|---|---|
name | 是 | 输入名。仅允许由字母、数字和下划线组成。 |
type | 是 | text、number、date、select 之一。 |
default | 否 | 非空时,当宿主省略该输入时使用。默认值会按该输入的 type 解析。 |
label | 否 | 面向人类的提示文本。宿主应当(SHOULD)将其作为表单标签。 |
description | 否 | 可选的较长帮助文本。 |
options | 否 | 当 type = select 时必需。以管道符分隔的允许值,例如 Seoul|Busan|Daegu。 |
实现必须(MUST)按表头文本(大小写不敏感)识别列。除上述列以外的列已保留,必须(MUST)被忽略。
当某行没有 default 时,该输入是必需的。宿主必须(MUST)为每个必需输入提供值;省略其中之一即为错误。
已解析的输入值通过 {{ __inputs__[name] }} 从单元格引用。例如声明为 name = month 的输入通过 {{ __inputs__[month] }} 引用。__inputs__[name] 解析为已解析并经强制转换的值;规范中没有在模板内部读取某输入的 label、default 或 type 的形式(宿主使用 readTemplateInputs() API)。
输入名不得(MUST NOT)与 __config__ 中声明为非系统行的作者自定义值发生冲突;这在解析时即为错误。
依 ADR-0062,当 default 单元格 —— 在 ADR-0050 求值之后 —— 按 ADR-0007 产出空值时,该输入即视为必需。"空单元格"、default = ""、default = " "、default = {{ "" }} 这几种形态都坍缩为"必需"。
依 ADR-0063,options 单元格在求值之后按 | 切分;每个元素去除 Unicode 空白后,空元素被丢弃。options = "Seoul | Busan" 产出 ["Seoul", "Busan"];options = "a||b" 产出 ["a", "b"];options = "||" 抛出 xl3/inputs/missing-options。重复选项会被保留。宿主提供的 select 值与产出的数组按大小写敏感方式比较。
输入值从宿主提供的值进行强制转换:
text—— 透传宿主字符串。非字符串的宿主值通过规范字符串形式(见 比较与字符串强制转换)字符串化。number—— 按"先 trim,再Number(),且不得产出NaN"解析。失败为错误。date—— 按日期格式单一表达式单元格相同的规则强制转换。失败为错误。select—— 宿主值在规范字符串形式归一化后,必须(MUST)等于声明的某个options。失败为错误。
经强制转换的输入值可以像任何其他值一样参与 IF()、@filter、&、比较运算和 TEXT()。