velocity模板不操作dom,而是生成合规xml文本:严格按xsd设计模板、后端预检必填字段、硬编码格式、全量转义、编码统一,并通过dom解析器最终验证。
velocity 模板引擎本身不操作 dom,它生成的是纯文本(xml 字符串),而 dom 是内存中的树状对象模型(如 java 的 org.dom4j.document 或 .net 的 xmldocument)。所谓“与 dom 节点深度结合”,实际是指:用 velocity 高效生成结构合法、内容合规的 xml 文本,再交由 dom 解析器加载验证或进一步处理;或反向——将 dom 解析出的数据对象注入 velocity 上下文,驱动模板生成定制化报表。关键不在“结合 dom”,而在“生成即合规”。
确保 XML 结构与语义双重合规
企业级 XML 报表(如税务申报、金融报文、电子凭证)往往有严格 Schema(XSD)约束。Velocity 不校验 Schema,但可通过以下方式保障输出合规:
-
模板即契约:严格按 XSD 定义的元素顺序、嵌套层级、必选/可选字段设计 .vm 模板。例如某报文要求
<header><reportid>...</reportid></header>,模板中不得省略<header></header>包裹,也不得颠倒子元素顺序 -
强制非空校验:在 Java 层对上下文数据预检,对必填字段抛异常或设默认值;Velocity 中用
#if($obj.field)避免空标签,但更推荐后端兜底 -
类型与格式硬编码:日期统一用
$dateTool.format('yyyy-MM-dd', $data.submitTime),金额保留两位小数$numberTool.format('#,##0.00', $data.amount),避免字符串拼接导致格式错误
安全转义 + 编码控制,杜绝解析失败
XML 对字符敏感,未转义内容会直接破坏结构。Velocity 提供原生支持:
-
声明即生效:模板首行必须为
<?xml version="1.0" encoding="UTF-8"?>,且 Java 初始化时显式指定编码:ve.setProperty(Velocity.INPUT_ENCODING, "UTF-8"); ve.setProperty(Velocity.OUTPUT_ENCODING, "UTF-8"); -
动态内容全转义:所有变量输出必须包裹
#escape.xml(),包括属性值和文本节点:<item id="#escape.xml($item.id)">#escape.xml($item.name)</item> -
CData 区块慎用:若需原样输出含标签的富文本(如备注字段),用
—— 注意:CDATA 内部不执行 Velocity 语法,$note 需提前在 Java 层转义
从 DOM 解析结果反向驱动模板
当已有原始 XML 需转换为报表格式时,可先用 DOM4J / JDOM 解析,再映射为 Velocity 可用对象:
-
扁平化封装:将
Document或Element封装成 POJO(如ReportContext),提取关键字段(header.reportId,body.items)并放入VelocityContext -
复用已有工具类:利用
Dom4jUtils.toMap(element)将节点转为嵌套 Map,Velocity 中可直接$data.header.reportId访问 -
条件渲染匹配业务规则:例如“仅当税额大于 0 时输出
<taxdetail></taxdetail>节点”,用#if($report.taxAmount > 0)控制区块
生成后交付前的 DOM 验证闭环
Velocity 输出的是字符串,最终 XML 合规性需由 DOM 解析器确认:
-
即时加载验证:生成文件后,立即用
SAXReader加载并设置 XSD:reader.setValidation(true); reader.setEntityResolver(new MyXsdResolver());,捕获SAXParseException -
错误定位到模板行:在 Velocity 模板中添加注释标记(如
<!-- REPORT_HEADER_START -->),验证失败时结合行号快速回溯模板问题点 -
响应头同步保障:若通过 Web 接口输出,HTTP 响应头必须设为
Content-Type: application/xml; charset=UTF-8,避免客户端误判编码










