标签属性默认值 TagDefault
适用模块:anyline-office(docx / xlsx 模板渲染) · 类:org.anyline.office.tag.TagDefault
1. 它解决什么问题
模板里的标签属性(如 <aol:for items="..." var="...">)通常要一个一个写在模板上。
当一批模板遵循同一套约定时(数据源都叫 items、循环变量都叫 item、无数据都不删行……),
可以用 TagDefault 在 代码里统一登记默认值,模板上就不必再写这些属性。
模板可以从这样:
<aol:for items="${items}" var="item" status="status" remove="false">${item.NAME}</aol:for>
简化成这样(属性全部由默认值提供):
<aol:for>${item.NAME}</aol:for>
只对"没写的属性"生效 标签上显式写了的属性永远优先,默认值不会覆盖它。
2. 优先级
- 标签上显式书写的属性(最高,写了就一定用它)
-
文件级默认值:
TagDefault.set(book.context(), "for.items", ...),只对当前文档生效 -
全局级默认值:
TagDefault.set("for.items", ...),对所有文档生效 -
内置默认值:代码中
BUILTIN预置的几条(见第 6 节,优先级最低) -
标签自身的缺省值:如
begin缺省0、step缺省1(兜底)
文件级之所以只对当前文件生效,是因为它借 Context.variables 传递:每个 WDocument/XWorkBook 各持有一个 Context,标签运行的子上下文由 clone() 继承,文件之间互不影响。
3. 三种设置方式
3.1 全局(对所有文档生效)
// 单条 TagDefault.set("for.items", "${items}");
TagDefault.set("for.remove", "false"); // 批量 Map<String,Object> defs = new HashMap<>();
defs.put("for.var", "item");
defs.put("for.status", "status");
TagDefault.set(defs);
3.2 文件级(只对当前文档生效,推荐)
XWorkBook book = new XWorkBook(template); // 注意必须在解析之前设置(save/open 之前) TagDefault.set(book.context(), "for.items", "${rows}");
TagDefault.set(book.context(), "for.remove", "false");
book.save(out);
3.3 直接给对象(不经过 EL 解析)
// 数据源可以直接给集合对象,不必先塞进上下文 TagDefault.set(book.context(), "for.items", dataSet);
4. key 的写法
-
格式:
标签名.属性名,大小写不敏感(内部统一小写),如for.items、chart.type。 -
别名自动匹配:取值时按代码里传入的别名顺序依次查找。例如
data, d, items, is会依次查for.data→for.d→for.items→for.is,命中即返回。 -
通配:
*表示对所有标签生效,如*.items;精确 key 优先于通配 key。
只登记主属性名 因为别名是按顺序抢先命中的,如果同时登记了
for.data 和 for.items, for.data 会抢在前面命中,你后来设的 for.items 就失效了。 一个属性只登记一个 key(主属性名)。
5. value 的三种形态
| 形态 | 写法 | 取值时的行为 |
|---|---|---|
| EL 表达式 |
"${items}"
|
按当前上下文解析成对象;解析不出来就是 null
|
| 普通字符串 |
"item" / "false"
|
原样返回(布尔/数字属性会再按类型解析) |
| 对象 |
dataSet / list
|
直接返回这个对象,常用作数据源 |
null 存不进去——传 null 等同于删除这条默认值。
6. 内置默认值
| key | 值 | 含义 |
|---|---|---|
for.items
|
${items}
|
不写数据源时,默认取上下文中的 items 变量
|
for.var
|
item
|
不写 var 时,迭代变量名是 item
|
for.status
|
status
|
不写 status 时,状态变量名是 status(${status.index})
|
它们是优先级最低的一档,可用文件级或全局级覆盖;想让状态变量回到老的 s:
TagDefault.set("for.status", "s"); // 全局
status 默认值变更提醒 内置
for.status 为 status。历史模板里"没写 status 却使用 ${s.index}"的写法会失效,
请在模板上显式写 status="s",或按上面一行代码把默认值改回 s。
7. 哪些属性可以设默认值
docx:标签的取属性统一走 AbstractTag.fetchAttribute*(),所以所有标签的所有属性都支持默认值。
xlsx:XRow 中 aol:for 的下列属性走默认值(data 系列单独按对象取值,见第 9 节):
| 属性 | 别名 | key | 说明 |
|---|---|---|---|
items
|
data d is
|
for.items
|
数据源(内置 ${items})
|
var
|
— |
for.var
|
迭代变量名(内置 item)
|
status
|
— |
for.status
|
状态变量名(内置 status)
|
remove
|
— |
for.remove
|
无数据时是否删除模板行,"false" 表示保留
|
begin
|
start b
|
for.begin
|
起始下标 |
end
|
e
|
for.end
|
结束下标 |
step
|
— |
for.step
|
步长 |
8. 完整示例
8.1 xlsx:一套约定跑所有模板
// 全局约定:数据源统一叫 items,无数据保留模板行 TagDefault.set("for.remove", "false");
XWorkBook book = new XWorkBook(template);
book.variable("items", dataSet); // 内置 for.items=${items} 会取到它 TagDefault.set(book.context(), "for.end", "99"); // 该文件最多渲染100行 book.save(out);
模板只需写:
<aol:for>${item.NAME}</aol:for>
8.2 同一模板渲染多次、每次不同约定
XWorkBook b1 = new XWorkBook(template);
TagDefault.set(b1.context(), "for.items", "${listA}"); // 只影响 b1 b1.save(out1);
XWorkBook b2 = new XWorkBook(template);
TagDefault.set(b2.context(), "for.items", "${listB}"); // 只影响 b2 b2.save(out2);
8.3 作用域 / 遍历范围(docx)
TagDefault.set(book.context(), "for.scope", "tr"); // 默认按表格行循环
9. docx 与 xlsx 的差异
| 项 | docx | xlsx |
|---|---|---|
| 覆盖属性范围 | 全部标签的全部属性 |
aol:for 的属性(见第 7 节)
|
| 数据源取值 |
data() → fetchAttributeData()
|
单独调用 TagDefault.fetch(),返回值可以是对象(DataSet/List),不走字符串转换
|
| 内置默认值 |
同一份 BUILTIN,两边一致
|
|
10. 删除 / 清空 / 查询
TagDefault.remove("for.items"); // 删一条全局默认值 TagDefault.remove(book.context(), "for.items"); // 删当前文件的一条 TagDefault.clear(); // 清空全局(不影响内置) TagDefault.clear(book.context()); // 清空当前文件 TagDefault.get("for.items"); // 查全局(不解析EL) TagDefault.defaults(book.context()); // 当前文件的全部默认值
内置默认值无法删除,只能用文件级/全局级覆盖。
11. 常见坑
-
写了属性但取不到值,不会再走默认值。
判断依据是"属性有没有出现在标签上",不是"有没有取到值"。items="${list}"而list不存在时,结果是空,不会被默认数据源顶替。 -
取不到数据源 ≠ 空集合。
变量不存在时aol:for只打一条 warn 并保留模板行;只有取到空集合时才按remove处理(默认删除模板行)。 -
文件级必须传该文档的 context。
要TagDefault.set(book.context(), ...);传错 context 就配到别的文件上(或完全不生效)。 -
设置时机要在解析之前。
new XWorkBook(file)之后、save()/open()之前设置。 -
别名别重复登记。
见第 4 节:for.data会抢在for.items前面命中。 -
xlsx 的
status默认已改为status。
老模板里${s.index}要么显式写status="s",要么TagDefault.set("for.status","s")。