最近的项目中有一个功能点为:根据分析数据库并生成报告。不过不是大数据、数据挖掘之类,报告的内容、组织方式都是事先固定下来的。实现的方式为,在普通word文档中插入书签制成模板,然后程序使用OpenXML解析文档,找到书签,并根据书签的意义进行相应的计算,最后用计算结果替换书签,替换的内容涉及到文本、图表、表格等。

  这一套已经可以稳定工作,但美中不足的是关于目录的问题,太长的文档开始有必要存在目录,但在模板中签入真实数据后,最后文档的篇幅每次都是不一样的,这就需要目录能都自动更新,但不知道OpenXML怎么实现(大侠遇到过的话恳请告知),最后找到了其它办法。

  第一种是使用宏。在模板中设置好标题并插入目录,然后在VBA编辑器中,双击This Document,添加如下代码:

Sub AutoOpen()
  Dim aStory As Range
  Dim aField As Field
     For Each aStory In ActiveDocument.StoryRanges
        For Each aField In aStory.Fields
           aField.Update
        Next aField
     Next aStory
End Sub

  目录属于域的一种,上面的代码大致意思是要求word在每次打开该文档时都遍历并更新每一个域,这样就把目录自动更新了。但这个方法在word禁用了宏时便会失效。

  第二种是手工修改word背后的XML文件,这个方法是看老外的一个视频学的,链接:http://ericwhite.com/blog/screen-cast-exploring-tables-of-contents-in-open-xml-wordprocessingml-documents/。不得不佩服,查找别的帖子的时候看到过视频作者的发言,这个Eric White之前也受困于这个问题,得到启示后把问题顺利解决,此外还做了这份非常细致的视频。

  要编辑所谓的“word背后的XML文件”,我的方法是把word后缀从"docx"改为“zip”,然后解压,记事本打开。Eric White的方法应该是用了OpenXML相关的插件,用vs可以直接打开word对应的xml文件并编辑,这个非常方便,可是我不会用唉。

  可以打开xml文件后,先修改settings.xml,在末尾加上一句  <w:updateFields w:val="true"/>,注意xml文件的层次。

  还要修改document.xml文件,找到目录所在的部分,不好找可以搜索w:fldChar,fldChar就是跟域相关的标签,模板中的每条目录都被包围在w:hyperlink标签之中,找到这些并删除,最终目录部分只留下这样的:

留意红框中的内容,最终相当于去掉了具体的目录信息,只保留了目录的框架。xml必须有闭标签,删除的时候留意别删错了,比如我当时的情况就是不小心把这个p标签删了。

  改好后,保存,重新压缩,将后缀改回“docx”便OK了。

  第一次打开会有询问是否更新域,选是。

以上便是这两种方法。各有优劣,对比一下

  方法一(宏) 方法二(修改XML)
失效 word禁用宏便会失效 不会失效
更新 每次打开自动更新 只在第一次更新
样式 可以设置目录的字体字号 不能修改目录样式

可以看到两种方法都不完美,应该还有更好的办法吧,请多指教。

代码操作Word时,目录自动更新的两种方法的更多相关文章

  1. 在PHP代码中处理JSON 格式的字符串的两种方法:

    总结: 在PHP代码中处理JSON 格式的字符串的两种方法: 方法一: $json= '[{"id":"1","name":"\u ...

  2. C#实现Dll(OCX)控件自动注册的两种方法 网上找的 然后 自己试了试 还是可以用的

    尽管MS为我们提供了丰富的.net framework库,我们的程序C#开发带来了极大的便利,但是有时候,一些特定功能的控件库还是需要由第三方提供或是自己编写.当需要用到Dll引用的时候,我们通常会通 ...

  3. C#实现Dll(OCX)控件自动注册的两种方法

    尽管MS为我们提供了丰富的.net framework库,我们的程序C#开发带来了极大的便利,但是有时候,一些特定功能的控件库还是需要由第三方提供或是自己编写.当需要用到Dll引用的时候,我们通常会通 ...

  4. mybatis学习之路----批量更新数据两种方法效率对比

    原文:https://blog.csdn.net/xu1916659422/article/details/77971696/ 上节探讨了批量新增数据,这节探讨批量更新数据两种写法的效率问题. 实现方 ...

  5. 实现Django ORM admin view中model字段choices取值自动更新的一种方法

    有两个表,一个是记录网站信息的site表,结构如下: CREATE TABLE `site` ( `id` ) unsigned NOT NULL AUTO_INCREMENT, `name` ) N ...

  6. PHP 操作MySQL时mysql_connect( )和Mysqli( )的两种报错机制

    刚开始使用PHP连接MySQL数据库的时候,如果数据库连接不成功或者,对MySQL数据库进行增删改查等操作的时候,SQL语句存在错误,而在执行PHP文件的时候,浏览器并不会抛出错误的原因,一般是空白显 ...

  7. qt 自动重启(两种方法)

    所谓自动重启就是程序自动关闭后在重新打开: 一般一个qt程序main函数如下: int main(int argc, char* argv[]) { QApplication app(argc, ar ...

  8. Zabbix 设置自动添加主机两种方法(自动注册、自动发现)

    在实际生产环境中,我们可能需要将很多台主机添加到 Zabbix Server 里,我们进行手动添加的话,会比较麻烦.费时,而且还容易出错.所以一般我们会设置主机自动注册.这样就比较方便. 官方文档链接 ...

  9. HDU 5596(更新,两种方法)

    更新: 这是中文题目的链接: http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=659&pid=1001 ...

随机推荐

  1. odoo开发笔记 -- 后台代码什么时候需要注意编码格式

    (1)首先py文件中的注释 中文汉字 一定要加u' ' (2) 前端视图不是多对一的时候,只是普通的字符字段 后台取值 需要加 str装换 head_node_dic['ManualNo'] = st ...

  2. MVC3学习:将excel文件导入到sql server数据库

    思路: 1.将excel文件导入到服务器中. 2.读取excel文件,转换成dataset. 3.循环将dataset数据插入到数据库中. 本例子使用的表格为一个友情链接表F_Link(LinkId, ...

  3. Python:快速查找出被挂马的文件

    网站被入侵,担心被挂马,因此就想自己写个脚本来查找那些被挂马的文件 思路 需要实现准备一份未受感染的源代码和一份可能受感染的源代码,然后运行以下脚本,就能找出到底哪些文件被挂马了. 其中,主要是根据比 ...

  4. unittest单元测试框架简单说明

    unittest单元测试框架不仅可以适用于单元测试,还可以适用WEB自动化测试用例的开发与执行,该测试框架可组织执行测试用例,并且提供了丰富的断言方法,判断测试用例是否通过,最终生成测试结果.今天笔者 ...

  5. CentOS7系统下YUM安装安装Mongodb 3.4

    第一步 查看是否存在Mongodb配置yum源 切换到yum目录 cd /etc/yum.repos.d/ 查看文件 ls 第二部 不存在添加yum 源 创建文件 touch mongodb-3.4. ...

  6. SpringMVC+FreeMarker+Mybatis 整合

    这个项目自己有时写写测试代码什么的, 代码比较简单,代码已放在 github : https://github.com/zhouyongtao/homeinns-web 目录结构: 贴一下Maven的 ...

  7. StreamSets学习系列之StreamSets支持多种安装方式【Core Tarball、Cloudera Parcel 、Full Tarball 、Full RPM 、Docker Image和Source Code 】(图文详解)

    不多说,直接上干货! Streamsets的官网 https://streamsets.com/ 得到 https://streamsets.com/opensource/ StreamSets支持多 ...

  8. 快速选择算法/Select 寻找第k大的数

    参考算法导论9.3节的内容和这位大神的博客:http://blog.csdn.net/v_JULY_v上对这一节内容代码的实现进行了学习 尝试实现了以查找中位数为前提的select算法. 算法功能:可 ...

  9. angular enter事件,angular回车事件

    angular回车键搜索,angular enter搜索 对于搜索框,用户在输入内容后的搜索习惯不是鼠标点击搜索按钮,而是直接按enter键,那我们怎么给enter键绑定事件呢,其实很简单,代码如下: ...

  10. 【LeetCode题解】225_用队列实现栈(Implement-Stack-using-Queues)

    目录 描述 解法一:双队列,入快出慢 思路 入栈(push) 出栈(pop) 查看栈顶元素(peek) 是否为空(empty) Java 实现 Python 实现 解法二:双队列,入慢出快 思路 入栈 ...