word、excel文档内容更新技术方案
需求背景
惯例先说下背景。
生产、研发业务上往往使用大量word和excel文档来作为资料载体,如操作规程、控制手册、卡片……,这些文档会反复使用到一些设备、工艺等参数数据。参数属性主要是名称、编码、正常范围、报警上下限、单位等,这些参数对应的属性值,是会发生变化的。
文档中使用参数的地方,中文的表达方式多种多样,人来阅读文档没啥问题。但是引用参数的文档,实际没有存在“物理”上的关联关系。当参数属性值调整时,需要更新相应的文档,这时候就出现问题了。因为没有关联关系,没有技术手段自动识别,只能人工一点点改文档,这工作量是相当大,找到需要修改的地方就不容易,并且很容易发生漏改、误改问题,从而导致不一致的问题。
解决方案
软件系统实现
很明显,这是一个模板技术的应用场景。解决该问题,常见的方案是通过软件系统来实现,实现思路如下:
1.对参数进行统一管理,作为管理的基础数据。实现上没什么好说的,常规的应用开发,增删改查,加其他必要的逻辑处理,可通过工作流实现参数的修订与审批,可通过平台实现数据权限控制。
2.对文档进行规范化处理,形成文档模板,通过模板技术,将参数数据填充进模板,生成最终的文档。简单点说,就是把文档中的使用参数的部分,使用约定好的标记来占位,如${HABC1234.name},然后程序替换。HABC1234是参数的唯一性编码,name是参数对应的名称。
3.引入全文搜索技术,使用elastic search,对文档建立索引,实现按参数编码检索该参数被哪些文档文档使用到了(这里实际检索的是文档模板,而不是最终的文档,模板里有参数编码信息,最终文档已经被数据替换了)。
以上基本能解决需求了,在这基础上,还可以做一些小工作,让业务用户使用起来更方便,例如:通过扩展参数属性方式,对参数的基本属性进行组合,如将常用的两个属性,名称和编码组合到一块去,文档中使用时,直接引用这个新属性
H
A
B
C
1234.
n
a
m
e
A
n
d
C
o
d
e
,
而不需要在文档里写
{HABC1234.nameAndCode},而不需要在文档里写
HABC1234.nameAndCode,而不需要在文档里写{HABC1234.name} {HABC1234.code}。
同理,可以进一步设置一些预置的格式化片段,如
编码:HABC1234
名称:风机温度
范围:20-50摄氏度
同样的,也可以对属性进行运算,例如,求合理范围的平均值。
office方案
通过软件系统解决有诸多优点,比如使用简单、管理规范、可扩展性高。但不得不说,软件系统也有一些缺点,比如成本高,交付周期比较长。上面提到,软件系统是常见方案,但放到特定的背景下未必是最优方案。这里说一种轻量级的解决方案,即通过office自身功能来实现。
开始的思路,依然是采用模板,使用office自带的脚本语言 vba来实现占位符的替换。在word中,占位符如何生成,找了下域对象,发现对应的对象。看来下标签,也不是干这事用的。经过长时间的搜索,发现word的一个生僻功能-链接,可以比较好的解决数据引用、关联和更新功能。说实话,这个功能以前从没用过,并且在word的菜单里找了半天,居然没有菜单与之对应。
实现思路如下:
1.使用excel作为参数的数据存储,相当于软件系统中的“数据库”。
2.引用到参数的文档,通过office自身功能,链接到excel的单元格。
3.参数数据更新后,通过office文档的更新链接功能来实现文档同步更新。
下面来说说具体链接怎么用。
先做一个存储参数数据的excel表,命名为“工艺参数清单.xls”,输入示例数据如下:
选中其中A1单元格,复制。
然后新建一个word文档,命名为“操作规程说明.docx”,打开,在word工具栏中选择“选择性粘贴”
在弹出窗口中将默认选中的“粘贴”,变更为“粘贴链接”,选择“无格式文本”,确定,效果如下:
这时候,excel单元格内容已经输出到word文档中了,并且关联了源数据,默认设置是自动更新,当excel里内容变化后,excel和word都处于打开状态,word文档会自动更新。不过当word文档处于关闭状态,这个更新还是需要一个触发,打开word文档后,会自动检测是否有链接,如有,则弹出对话框选择,选择是即可完成更新。
按照上述操作,在word文档中,已经建立了到excel单元格中数据的关联,这个连接实际保存在word文档中,也就是单向链接,excel中不知道被哪些文档引用过,但word中知道自己引用的数据源是哪个。
在链接上右键点击,可出现菜单“更新链接”,以及“链接的工作表对象”,前者作用是看名字即可,后者可继续展开二级菜单,选择编辑链接 或 打开链接 ,会自动打开对应的excel表。选择“链接…”,则会显示本文档使用的所有链接清单。
从上图可以看出,链接的实现机制是关联了磁盘上的excel文件,并且使用了绝对路径,单元格的引用遵循了sheet名+行号+列号的方式。
以上操作,也适用于excel类型的文件,链接到另外一个excel文件的单元格,操作上略有差异,比如选择性粘贴的时候,弹出的对话框中粘贴链接在左下角,如下图:
粘贴后,可看到该链接的形式如下:
查看所有链接,在工具栏里找到了对应功能按钮来打开对话框。
通过以上方式,实际已经实现了维护参数基础数据,并保持文档自动更新的目的。
但是,仅仅做这些其实还不够,需要一些额外的工作来弥补这种轻量级实现方式的一些不足。
首先,关联是引用了绝对路径,因此要求作为数据源的excel文件,磁盘位置和文件名均需要保持不变。特别是多人协作的时候,需要每个人的磁盘存放位置也一致,比如都在C盘或D盘建一个根目录来统一存放,这点需要从管理上来规范。
其次,关联是单向的,如果是参数文件修改了,其实并不知道哪些文档引用了这些参数,总不能把文档全部手工打开一遍,来完成更新吧?文档数量如果是几千份,是不是就疯掉了?这时候,就需要使用vba脚本,写个循环,遍历所有文档,调用更新链接操作,这个脚本我没有实际写,但关键的技术问题做了个验证。
Sub updateField()
Dim aField As Field
Dim aStory As Range
''' Update all fields in the document
For Each aStory In ActiveDocument.StoryRanges
For Each aField In aStory.Fields
aField.Update
MsgBox (aField.Code)
Next aField
Next aStory
End Sub
以上测试代码能正常完成数据更新,结合目录文件遍历就能实现一个完整的脚本了。从这里也可以看出,链接,本质上是word中域的概念,跟目录、页码等是一回事。