工作中遇到一个需求:写个nodejs脚本,对word文档(1000+个)的目录页面进行美化。实现过程遇到不少麻烦,在此分享下。
整体思路
众所周知,Docx格式的Word文档其实是个以xml文件为主的zip压缩包,所以,页面美化整体思路是:先将文档后缀名改为zip并解压到本地,然后将关键的XML文档解析为DOM树,再通过DOM操作对文档进行编辑,最后把修改好的内容替换到原文件中,打包好并恢复后缀名。
其中,难点在于“文档编辑”,网上基本搜不到有用的资料,只能自行摸索,主要用到的依赖包为 cheerio,作用是用DOM的方式加载和操作XML文档,函数方法类似jQuery。(解压打包等常规操作,下文忽略)
一、定位目录内容
将Word文档解压后,内部一般会包含上百个文件,其中,文档的文本内容均位于“word/document.xml”中;
目录中的文本都是一句占据一行,所以每句文本都包含在一个单独的段落中(<w:p>标签),而且它们还具有锚点特性,所以文本外层还有个< w:hyperlink >标签,通过这两个特点,我们可以获取到所有目录节点;但因为目录页的标题“目录”二字是没有链接的,所以还需要在第一个“w:hyperlink”标签之前找到目录二字所在的段落,以便后续进行操作。
二、修改文字颜色粗细
如图所示,Word文档中的实际文本都是放在<w:t>(t指代text)标签中的,而<w:t>又是放在<w:r>(r指代range)中,而<w:r>还会包含一个<w:rPr>标签,它里面存放的是文本的样式。此处我们想设置一级标题的加粗和变色,只需要在当前段落的每个<w:rPr>中添加<w:b/>和<w:color w:val=”019988″/>即可。
这里,因为我们要修改的只是一级标题,所以要对标题层级进行区分, 通过观察对比可以发现,不同层级的<w:pStyle>的w:val属性值不同,而且第一个< w:hyperlink >所在的段落通常就是一级标题。
三、在文档中插入图片
插入图片涉及多个目录、文件:
1)word文档中的图片统一放在“word/media”目录下,默认名称为“image+数字”;
若目录不存在,需要自行创建;另外,为了避免与已存在的文件名冲突,不建议使用“image+数字”的命名方式。
2)须在“[Content_Types].xml”文件中添加类型声明(声明一次即可);
需判断是否已存在相同后缀的图片类型声明,则不必再添加。
3)须在“word/_rels/document.xml.rels”中建立索引关系,每个资源对应一个唯一的rId;
4)使用rId和相应的标签将图片插入到“word/document.xml”文档中。
图片的标签结构比较复杂(外层通常是一个<w:drawing>标签),可以在同一个文档中先手动加一个测试图片,然后在xml中复制图片的代码块进行修改,为我所用。
四、特定页面设置背景图
Word添加水印虽然可以设置背景图,但是需要添加分节符,代码改动也比较大;这里我采用的方式是“插入图片+图片衬于文字下方”。代码也是在文档中添加一个<w:drawing>标签,只是内容略有不同,代码模版也可以通过添加测试图片的方式获取。
附:调试技巧
1)因为Word文档解压后的文件众多,而且稍微修改点东西后,受影响的文件也特别多,比对解压文件的时候很麻烦。我这里是随便找了个git项目,然后将原始的Word文档解压文件提交到本地仓库,然后再把修改后的文档的解压文件覆盖上去,用git辅助对比。
2)初始可以用空白文档(有个空格或者一个字母即可)进行测试,可以避开很多干扰元素。
3)对修改后的解压文件,可以用逐个回退的方式确认哪个文件的修改不是必须的。某个文件回退后,再打包改后缀,如果文档可以正常打开则说明它的变化不是必须的。