(说的有点儿乱,有时间做图之)
一个rtf文件差不多长这个样子
{\rtf1\***
{\field***} //这是一个Word中的域定义,它是一个1级块;
\**\**\** //这是一个NB_String块(无花括号)
{\*\atrfstart} //这是批注头,也是一个1级块
{\rtlch\fcs1 \** \'b0\'fc} //这是一个常见的文本定义,后方的16进制代码就是用Word打开能看到的文本
\**\** \**
{\rtlch\fcs1\***{\*\atrfend 274729727}{\***}{\***{}}} //这是批注尾,看以看到它内含{\*\atrfend274729727},这个就是个2级块
{\*\datastore ****}
}
--名词解释:
*块:Block,对一个Rtf按{}进行递归解析,会发现它是一个由{/rtf1***}为根的树状结构。这样,对于Rtf中由{}限定的一段Rtf字符串,就称之为块。
广义来讲,基于OO的思想,Rtf中1级块中NB_String型的也把它算做块;这样整个rtf就是一个块。
* 1级块:rtf这个块可以称之为0级块,相应的它的下一级子结点,称之为1级块,依此类推,也可以定义出2级块、3级块。1级块是本技术实现的重点分析对象。
* NB_String(No Brace String)块:1级块可以分为含有{}的和不含{}的,不含{}的1级块则是NB_String型的。
* 域变量(MergeField):
{\field{\*\fldinst {\rtlch\fcs1 \af0\afs30 \ltrch\fcs0 \fs30\kerning2\loch\af0\dbch\af35\insrsid4944230 \hich\af0\dbch\af35\loch\f0 MERGEFIELD "ACCOUNT_NAME" }}{\fldrslt {\rtlch\fcs1 \af0\afs30 \ltrch\fcs0 \fs30\lang1024\langfe1024\kerning2\loch\af0\dbch\af35\noproof\insrsid4944230 \loch\af0\dbch\af35\hich\f0 \'ab\loch\f0 \hich\f0 ACCOUNT_NAME\'bb}}}
* 批注变量(MergeField):
{\*\atrfstart 271807552}
……中间是批注内容……
{\*\annotation{\*\atnref 271807552}{\*\atndate 1726397554}\ltrpar \pard\plain \ltrpar\s35\ql \li0\ri0\nowidctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs21\alang1025 \ltrch\fcs0 \fs21\lang1033\langfe2052\kerning2\loch\af0\hich\af0\dbch\af13\cgrid\langnp1033\langfenp2052 {\rtlch\fcs1 \af0 \ltrch\fcs0 \cs34\insrsid996054 \chatn }{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid996054 \hich\af0\dbch\af13\loch\f0 ADDRESS_LIST}}
注:为什么使用MergeField、批注来做变量块?
这是是因为
1.“制作方便”:用Word打开一个Rtf,插入一个域和批注是很简单的事情;;
2.“易于检查”:肉眼检查手
3. 反观用特殊标记来做变量的,就做不到这两点:
想像用Txt编辑器打开一个RTF?
在茫茫RTF的天文里面定位要插入变量的地方?
制作好了去检查插入的对不对?插入的特殊标记可能是非RTF编码,可能制作好的模板都打不开……
--动态Word模板制作及开发流程
1.制作模板
* 域变量制作规则:在光标处,按 CTRL + F9 快捷键,然后输入“MERGEFIELD”+“变量名”(例:MERGEFIELDACCOUNT_NAME),输入完成后按 SHIFT + F9 或直接按 F9 即可。注意,MERGEFIELD关键字全大写
* 字符规则:限定“数字”、“大写字母”、“下划线”,首字符限定“大写字母”
* 批注变量制作规则:若某些内容存在多行循环打印或需根据条件判断是否打印,则需要在模板中采用“批注”方式标识这部分内容,作为“批注变量”(以“_LIST”命名结尾),并在该文档中将其变量串中包含的变量与相关打印规则(如换行打印等)、模式进行说明
2.模板检验
* 使用模板校验工具检查模板中的“批注变量”、“域变量”是否正确,这包括:
变量是否可识别
变量名称是否识别正确
批注变量圏起的范围如预期所想
3.模板对应Dto制作
* 主要是批注变量内的多个变量需要做成一个Dto
* 如果批注内只有一个域变量,可以不做对应Dto,直接做一个List<String>塞入参数Properties即可
4.模板打印开发
* 模板转换为一个实际文档,数据源是一个参数Properties
* 1级变量直接塞入参数Properties中即可,名称需要与模板中一致
* 变量取值优先取当前对应Dto中的,找不到则从Properties中查找
如果一个变量在一个模板中要打印多次(无论在什么位置,哪怕在多级嵌套的批注中),在Properties中塞入一次即可
* 批注要做成一个List,List名称要与模板中批注内容一致,List中的元素(Dto)可以任意命名
* 剩下的就是根据实际逻辑塞值了
--类说明
RtfUtils.java
*校验功能
*格式化功能
* 多Rtf合并
* 模板输出
* 页眉页脚替换
* 水印内容替换
BlockUtils.java
* 实际Rtf块(Block)的处理
* 块类型,名称识别
BlockType.txt
* 定义块类型
MERGEFIELD,annotation,atrfstart,headerr,footerr,ltrrow,cell,nestrow,nestcell,pnsecl
ModifyWords.txt
* Rtf Key Words的正则表达式,用于提取块的名称及类型
Rtf.properties
*常用的Rtf格式定义
SECTION_BREAK,CN_HEAD
BlockDto.java
String id;对于批注,它的头和尾都有一个唯一编号
String name;块名称
String value;对于MERGEFIELD,实际值
String type;块类型,取自BlockType.txt
String oriStr;块原始Rtf串
BlockDto pre;它的上一个非NB_Stirng的Block
BlockDto next;它的下一个非NB_Stirng的Block
AnnotationDto.java (extends BlockDto) * 批注类型变量
BlockDto start;批注头
BlockDto end; 批注尾
List<BlockDto> contentList;块中内容