开源Word读写组件DocX 的深入研究和问题总结

一. 前言

前两天看到了asxinyu大神的【原创】开源Word读写组件DocX介绍与入门,正好我也有类似的自动生成word文档得需求,于是便仔细的研究了这个DocX。 我也把它融入到我的项目当中并进行了实践。工具果然牛叉,但也有一些问题,后边一并列出来。

二. DocX的基本原理

Word有一个开放的文件格式,叫做Office Open XML。Office 从2007版本开始用它。它的基本方法是将文本和格式存储成xml,把其他资源(图片等)存储成独立文件,并将其进行Zip压缩。这样的好处是它的体积远比03版本的office文件小得多,但也造成了一部分不兼容性。因此,别指望DocX支持Office2003.

当理解Word实质上是XML以后,就不难了解如何操作Word了。理论上说,你不需要任何工具就能对它进行操作,当然复杂性极高。微软推出了Open XML SDK, 专门帮助.NET语言与Office实现互操作,这也成了COM组件外的新选择,但它的安装包有100M, 对很多部署来说,难度不小。

这个组件DocX本身实际上是对XML操作的封装库,如果你有兴趣看它的源代码,基本核心就是XML的字符串组装和拼接,添加一个图表的本质就是在对应XML标签下面再增加一个图表的子文档。

看到字符串拼接,有经验的同学肯定站出来会问性能如何。它没有使用StringBuilder,但本身性能不差,我生成100页的图文并茂的Word文档也是瞬间的事情,所以,没有关系。

三. 自动文档生成的方法

对程序开发来说,,最常见的需求便是自动生成文档,完全从0生成图文并茂,排版合理的文档对程序员来说不现实,代码多得海了去了。所以很多人的做法是字符串替换,通过替换特定文字来操作,但这样显然是相当不专业的。

比较合理的做法,是Office里面的“域”。域的本质,对程序员来说就是表达式,这个变量可以是文档字数,文档页数(这是Office里面自带的属性)。域相当牛逼,甚至可以连接到一个数据库,一个按钮,乃至一篇网页上去,真心无所不能。

同样你也可以自己添加属性,也就是所谓“自定义属性”。

如何查看文档中的所有自定义域呢?

在Word最上面的“插入”卷展栏下选择文档部件->域,如下图所示,并在域控制框中左侧选择DocProperty,即可看到所有的属性:

怎么在文档中插入一个自定义域呢?一种做法是,随便在上图中选择一个域(比如Author),点击确定,就会在插入的位置生成一个域。 然后点击右键,选择‘切换域代码’,即可改变里面的域定义:

修改Author,变成你想要的属性,就可以了,把这个东西拷到别的地方,再修改下域代码,就是一个新的域定义了。这些域定义,可以被我们用程序操作来替换。

由于域实质上是表达式,所以涉及一个计算过程。可以选择打印时自动更新,或者Ctrl+A全选,然后F9,就可全部更新所有域表达式。

至于如何在程序中操作域,【原创】开源Word读写组件DocX介绍与入门已经介绍的很清楚了,就是变量赋值,你可以在表格中添加域,然后就动态填写了表格。所以就不介绍了。

但是,在实际开发中,有个致命的问题: 当你通过模板,为自定义属性赋值,生成新文档后,打开新文档这些域并没有自动更新,这是非常麻烦的,因为客户可不想打开文档后发现那些核心数据都是奇怪的东西,让他们去摁F9自动更新域更是不可能。但要命的是,有些域被更新了,有些域没有更新,从域定义上来看,没有任何区别,这到底是怎么回事? 如果有大神解决了这个问题,请不吝赐教!

四. 插入图表的困扰

说到这里,有一个良好排版的模板,加上自动替换的功能,文档生成应该差不多了吧?不,还要插入图表和图片,这些用域暂时还不好解决。

插入图片的问题,关键是插入位置,你需要找到要插入的位置所在的段落(Paragraph).我的做法是,用Linq查询,通过定位关键字的做法找到段落,然后插入之即可。虽然粗糙,但还能用。插入表格类似。

但,怎么插入图表?所谓图表,就是柱状图饼状图等等的东西?虽然官方示例里有生成图表的功能,但我用Word2013怎么都打不开: “该文档有问题”。百思不得其解,花了半天才在别人的2010上打开,大喊坑爹(因此,DocX对Office2013的兼容性不够!)

那好吧,我们用Word2010或者07总可以了吧?但目前版本的源代码,只能往文档的最后添加图表,因为只有一个这样的函数:

这不是坑爹呢么?另外有时候插入图表或图片会出错,显示XML错误,建立连接的ID重复! 更是坑爹。

在这个地方会抛异常。

经过分析,是上面那个生成RelationshipID的函数出错了, 后来,索性改了这个函数的方法,直接从GUID生成,这样就不会错了,代码如下。

修改RelationID生成函数

至于只能在文档最后添加图表的问题,我做了以下的代码修改:

在指定位置插入图表

和源代码对比,很容易就能看出两者的区别。

我能添加更多的图表吗?当然可以。源代码只内置了三种图表:Pie, Line和Bar,不能满足要求,既然充分理解了它的原理,不妨我们扩展它吧:

总结成功的经验能够让人越来越聪明,

开源Word读写组件DocX 的深入研究和问题总结

相关文章:

你感兴趣的文章:

标签云: