在跨平台环境中实现写word时,如果用现成的库,就会涉及跨平台兼容性问题,比如在安卓与java中实现写word的功能。还有一个问题就是,完全用程序生成word文档,工作量较大。所以采用了模板替换的方法。
docx文档本质就是一个zip文件,只要将它的扩展名改成zip,就能解压出一系列的xml文件与图片文件,它的目录结构如下:
-
[Content_Types].xml:定义了文档中所有文件的 MIME 类型。
-
_rels/:包含了文档的元数据和关系信息,有一个特殊的文件
.rels
,定义了文档的内部链接和外部链接。 -
docProps/:这个文件夹包含文档的属性信息,如标题、作者、主题等。
- app.xml:包含应用程序特定的属性;
- core.xml:包含核心属性,如标题、作者、创建日期等;
- custom.xml:包含自定义元数据。
-
word/:这个文件夹包含文档的主要内容和设置。
- document.xml:这是文档的主要 XML 文件,包含了文本、样式、段落、表格和其他内容;
- footer1.xml:页脚;
- header1.xml:页眉;
- styles.xml:包含文档中使用的样式定义;
- settings.xml:包含文档的设置,如页面布局、标题等;
- fontTable.xml:包含文档中使用的字体列表;
- numbering.xml:包含文档中的编号格式定义;
- theme/:包含文档的主题信息,如颜色方案、字体方案等;
- media/:包含文档中使用的图像和其他媒体文件。
DOCX 文件的 XML 结构是层次化的,通常以 w:document
作为根元素,然后包含以下主要部分:
- w:body:包含文档的主体内容,如段落 (
w:p
)、表格 (w:tbl
)、图片 (w:drawing
) 等; - w:p:段落元素,包含文本和格式化信息;
- w:r:运行元素,表示文本的一段连续区域,可以包含文本 (
w:t
) 和格式化信息; - w:t:文本元素,包含实际的文本内容;
- w:tbl:表格;
- w:tr,w:tc:表格中的行与列。
每个 XML 文件都遵循 OOXML 的命名空间规则,并且使用特定的 XML 模式进行定义。
主要内容在word目录下,通常关注word目录下的document.xml,header1.xml、footer1.xml以及media子目录下的图片文件。
在程序中产生的数据,通常是规则的,比如表格数据(如下图),非常适合传给freemarker,由它替换到word目录下三个xml文件以及media子目录下的文件。注意:图片不能用base64格式,需要将它转成二进制格式,一个小遗憾,如果能用,模板定义就更简单了。
模板制作方法也很简单:用office或wps写一个文档,定义好格式,在需要占位的地方写上特定的内容(只要在xml中容易找到就可以)。然后将docx扩展名改成zip,解压后,在word目录下的document.xml,header1.xml、footer1.xml中,将内容都改成指定的占位符就行了。
freemarker的语法这里就不介绍了。freemarker在安卓中有点点问题,具体不记得了。我用的是js,把几个xml文档改成js程序,样例如下:
var xml=[];
xml.push(`....`);
if(conditions...) xml.push(`....`)
.....
xml.join('');//输出最后的内容
把它们放到一个js引擎中,比如graalvm的js引擎,安卓上的quickjs引擎等,因为都是基本js语法,不会有兼容性问题。js执行的最终输出结果就是所需的xml文档。
生成完毕,按原来的结构压缩成zip包,再改成docx扩展名就可以了。
至简网格的服务器要在java与安卓中都能运行,兼容性就是个大问题,并且资源占用不可能像普通服务器那样没有节制,所以用的就是这种方法。因为本身要用js引擎做接口实现的扩展,所以js引擎是必须的,顺带着,部分模板就用js实现拼接。