阅读目录

  • Word二次开发概况
  • 使用DsoFramer进行开发
  • 使用Interop进行开发
  • 打开、关闭和写入操作
  • 批量替换文本
  • 遍历段落替换文本
  • 查找后逐个替换文本
  • 结论

在各类应用系统开发中,和Word相关的应用可谓相当广泛。如各类MIS系统、各种和实际业务结合紧密的系统、需要制式报表的系统等,都需要对Word进行操作,典型的应用包括:

1、内嵌Word。在系统中内嵌Word,这样,既可以利用Word强大的功能进行文档的新建、编辑、修改、排版,同时还节省了用户对于编辑器操作的学习成本,提高了文档格式的通用性。

2、Word的二次开发。通过Word自带的宏,利用VBA(Visual Basic Appplication)进行开发,实现各种复杂的自动化功能。

3、前台不显示Word操作界面,而在后台对Word文档进行操作。包括:1)读入word文档,解析内容,获取需要的数据;2)把数据写入Word模板,生成符合格式要求的Word文档。

上述应用中,前两个应用领域相对特定,且需要对Word进行深度的二次开发,本人涉猎有限,因而不进行过多的讨论。而对于第三种应用,由于Word软件的普及率非常高,基本上可以把DOC文档看作是一个通用的文档结构。同时,Word在格式控制方面功能非常强大。因此,使用Word来制作输出文件或者报表,不光格式易于控制(用户可以在Word中制作好需要的模板,替换真实数据就获得需要的输出文档或者报表),用户的接受度等方面都有很大的优势,近年来越来越受到重视。下文主要尝试讨论如何利用Word模板生成需要的Word文档的实现。

回到顶部

Word二次开发概况

1983年,微软发布了基于MS-DOS的Word 1.0版,至今已经30余年了。对于Word的二次开发,也是有着悠久的历史。就本人的开发经验而言,在近十年前,就已经在Visual Basic 6.0平台上,进行内嵌Word的开发,这个在当年也是非常流行的一种开发。时至今日,Word的二次开发仍然是每个开发者频繁遇到的问题。

但是,Word的开发相对于其他的二次开发,甚至于相对于同门的也很复杂的Excel来说,开发的难度都要大很多,原因来自以下方面:

1、Word 的对象结构复杂。由于Wrod有着久远的历史,这既是它的优势也是它的包袱,它必须要保持足够的兼容性,因此DOC文档结构也就变得非常的复杂了。在Word中,有着复杂的对象结构,如Application、Document、BookMarks、Range、Selection、Paragraph等,它们之间既有层级关系,还有嵌套关系,有时为了一个小小的功能,却无法找到操作的对象。

Word 的对象结构

2、Word功能复杂。作为微软的拳头产品,多年以来,Word的功能越来越强大。尽管大多数的功能对于二次开发来说是完全用不到的,但还得去了解和学习,这就需要付出额外的代价。以Find为例,其参数竟然高达15个,如下所示:

Find.Execute(FindText, MatchCase, MatchWholeWord, MatchWildcards, MatchSoundsLike, MatchAllWordForms, Forward, Wrap, Format, ReplaceWith, Replace, MatchKashida, MatchDiacritics, MatchAlefHamza, MatchControl)

但大多数情况下,我们只会用到FindText、ReplaceWith等极少数参数而已。

3、版本问题。Word的众多版本也给二次开发带来很多困扰,开发者必须要对于当前多种Word版本都存在的情况有所考虑,并做好兼容性的处理才行。

回到顶部

使用DsoFramer进行开发

谈到Word的二次开发,就必须要提到DsoFramer。它是微软提供一款开源的用于在线编辑、调用Word、 Excel 、PowerPoint等的ActiveX控件。国内很多著名的OA中间件,电子印章,签名留痕等大多数是依此改进而来的。

DsoFramer操作Word很简单,加载ActiveX控件后就可以直接操作Office文档了。以我们要进行的主要操作——替换文档中的关键字为例,在Visual Basic中代码如下:

dso.Open "new.doc" dso.Replace "[标题]","新标题",3 dso.Save "c:\new2.doc" dso.Close

在VB6中加载控件,如下图所示:

由于DsoFramer是COM时代的产物,适用于VB、VC开发者,在 .Net下开发,或者进行Web应用开发,就显得有点力不从心。在实际开发中,常常出现一些莫名其妙的错误。另外,它的工作模式需要先在界面中打开文档再进行各种操作,这种模式也不适应Web应用程序的需要。

回到顶部

使用Interop进行开发

微软在.Net框架下,推出了Microsoft.Office.Interop.Word及其他的互操作方式,能够更好地对Office文档进行二次开发。

使用Interop进行二次开发,首先需要了解Word的对象结构,完整的Word对象结构图如下(来自官方的VBA_Word帮助文件):

Application: 用来表现WORD应用程序,包含其它所有对象。他的成员经常应用于整个Word,可以用它的属性和方法控制Word环境。

Document对象: Document对象是Word编程的核心。当打开一个已有的文档或创建一个新的文档时,就创建了一个新的Document对象,新创建的Document将会被添加到Word Documents Collection。

Selection: Selection对象是描述当前选中的区域。若选择区域为空,则认为是当前光标处。

Rang: 是Document的连续部分,根据起始字符的结束字符定议位置。

Bookmark: 类似于Rang,但Bookmark可以有名字并在保存Document时Bookmark也被保存。

回到顶部

打开关闭和写入操作

了解到Word的对象结构后,就可以考虑怎样操作了。

1、如何打开和关闭Application及Document对象。

打开和关闭操作比较简单,实现代码如下:

//打开 Microsoft.Office.Interop.Word.Application app = new Microsoft.Office.Interop.Word.Application(); Microsoft.Office.Interop.Word.Document doc = app.Documents.Open(ref fn, ref oMiss, ref oTrue, ref oMiss, ref oMiss, ref oMiss, ref oMiss, ref oMiss, ref oMiss, ref oMiss, ref oMiss, ref oTrue,ref oMiss, ref oMiss, ref oMiss, ref oMiss); //关闭 doc.Close(ref oFalse, ref oMiss, ref oMiss); doc = null; app.Quit(ref oFalse, ref oMiss, ref oMiss); app = null;

2、写入

由于Word的结构复杂,要找到写入的位置就比较复杂。在Interop操作中,可以对Range的text进行操作,如:

doc.Range.Text="newtext";

回到顶部

批量替换文本

写入报表,最常用的方法,是把模板做好,定义好特征串,进行替换即可。自然而然我们想到了通过Word的替换功能来完成。其主要代码如下:

object s1 = OldString; object s2 = NewString; object rep = Microsoft.Office.Interop.Word.WdReplace.wdReplaceAll; doc.Content.Find.ClearFormatting(); doc.Content.Find.Execute( ref s1, ref oMiss, ref oMiss, ref oMiss, ref oMiss, ref oMiss, ref oMiss, ref oMiss, ref oMiss, ref s2, ref rep, ref oMiss, ref oMiss, ref oMiss, ref oMiss);

用简单的字符串测试,代码工作正常,但是,用实际的数据测试发现无法完成替换。追踪后发现问题:替换的目标字符串不能过长,否则就会替换失败,这个结果和Word软件中替换的实际情况一致。

回到顶部

遍历段落替换文本

由于批量查找替换操作不能完成替换成长文本目标,直观的解决思路就是采用手动的方式,找到一个特征串替换一个。但是在Interop中,由于Find对象比较复杂,多次尝试没有成功,比较实验后,发现可以采用遍历方式进行替换。

由于文档下有多个段落,因而可以对文档中的每个段落进行遍历,如果在段落中找到特征串,就把段落的文字提取出来,放在字符串中,对该字符串进行替换后再重新赋值给这个段落。这种方式需要段落的格式保持一致,这样就可以拼出完成段落来了。核心代码如下:

for (int i = 0; i < doc.Paragraphs.Count; i++) { try //只能用尝试的方法来进行替换 { if (doc.Paragraphs[i].Range.Text.IndexOf(OldStringArray[k]) >= 0) { doc.Paragraphs[i].Range.Text = doc.Paragraphs[i].Range.Text.Replace(OldStringArray[k], NewStringArray[k]); } } catch { } }

在实际操作中,发现遍历操作非常容易出错,原因在于文档对象存在着很多的段落,超过了可以看见的段落数量,因此就必须加入一个错误捕获功能以忽略一些意外的错误。

通过这种替换,可以成功的完成整段的替换,效果如下图:

如果被替换的特征串并不是独立的段落、或者位于表格中的话,上述代码能否工作正常呢?如下图所示,在段落中和表格中增加两个特征串进行替换,结果如下图所示:

结果可以看到,表格中虽然顺利替换,但格式还是受到影响。而段落中的文字虽然替换了,格式也被改为统一的格式了。

回到顶部

查找后逐个替换文本

对于一个追求完美的程序员来说,上述的bug是无法容忍的,尽管它已经可以凑合使用了,但要忽视的确做不到。根据前面的铺垫,可能感觉到问题的解决还得把Word的内部构造搞清楚。

在网上搜索了很久,都没办法找到关于查找和替换的更详细的解决方法。经过一段时间的困惑之后,突然发现,其实这些资料我自己本身就有。就是使用VBA开发Office的一系列资料,里面关于Word的对象结构,有着远比网上只言片语靠谱的解答。学习的过程直接跳过,把几条重要的结论给出来:

1)用Content的Find查找,只能进行批量的查找和替换,如果想找到第一个,停下来,操作,是不行的。

2)上述的“查找——操作”的思路,只能用Selection对象来完成,而Selection对象,Document的属性中没有、Content的属性中也没有。只有谁有?Application!

3)用Application的Selection的Find找到后,结果就在Selection.Text中,但要替换,只能对Selection.Range.Text进行赋值才行。

下面是实现代码:

object oFindText=OldString; app.Selection.SetRange(0, 0); app.Selection.Find.Execute(ref oFindText,ref oMiss,ref oMiss,ref oMiss,ref oMiss,ref oMiss,ref oTrue,ref oMiss,ref oMiss,ref oMiss,ref oMiss,ref oMiss,ref oMiss,ref oMiss,ref oMiss); if (app.Selection.Find.Found) { app.Selection.Range.Text=NewString; }

再次对上述第二种模板进行替换,结果如下:

这段来之不易的代码,当然要保存在CommonCode(v2.0.6)中,以后要调用Word模板实现生成新文档就非常简单了,代码如下:

CommonCode.WordUtil.ReplaceAndSave(Application.StartupPath + "\\temp2.doc", Application.StartupPath + "\\1.doc", new string[] { "[%单选%]", "[%分数%]", "[%数量%]" }, new string[]{@"
1、关于公开信息搜密,正确的是
A.在互联网公开信息中搜密需要高深的技术
B.在互联网中的主流网站中不存在秘密
C.只要通过关键词搜索和定期跟踪网站就可能找到秘密信息
D.公开信息搜密因为方法简单,所以效果较差,不受重视","98","10"});

回到顶部

结论

对于替换Word模板内容生成Word文档的需求,在.Net下可以采用Interop的方式来实现。具体的实现手段,有批量替换、遍历替换、单步查找并替换等方式。批量替换不能进行长文本的替换故不可用,遍历段落替换不能对段内的关键词进行保持格式的替换,也不完美。单步查找替换调用全局的查找功能(app.Selection.Find),并能够定位查找到的内容并进行操作,是完成需求的最佳方案。

单步查找替换实现方案被整合至CommonCode.WordUtil.ReplaceAndSave函数中,可以直接使用。

Demo下载

说明:引用CommonCode.dll和Microsoft.Office.Interop.Word.dll即可。

原来demo缺了log4net引用,添加

demo-2

【3】利用Word模板生成文档的总结相关推荐

  1. java使用POI根据word模板生成文档,并且根据参数值实现换行

    一,word模板如下 二,将word模板中的参数对应的值放到map中 /*** 将word模板中需要的参数值统一放到map中* * @param resource* @param template* ...

  2. java根据word模板生成文档(含文本替换和动态生成表格)

    开发功能需求:给定word模板,word模板中存在"${XXX}"格式的需要变量替换的一些词,包括直接可以被替换的词,需要循环获取.替换.格式处理的词(例如根据数据库存储内容循环生 ...

  3. 通过Excel+Word批量生成文档及批量提取和修改文档名字

    excel和word是日常的办公软件,最近老师给了我一个任务,任务内容如下: 给了我一个班级同学成绩单excel表格和一个给家长的一封信word模板,在word模板中有相应的成绩表格要填写,即:我要去 ...

  4. Microsoft.Office.Interop.Word通过模板生成文档出现的问题经验总结

    本人在Word 模板导出时存在的问题主要有两个方面(我使用的是办公软件是WPS): 1.在本机可以正常导出,IIS发布后导出失败!报错信息是:检索 COM 类工厂中 CLSID 为 {000209FF ...

  5. jacob根据word模板生成文

    最近的任务要求根据word模板生成检查报告,选择使用jacob,它对word的支持还可以,它是Java-COM中间件,通过这个组件可以调用COM组件和Win32程序库. 因此它在环境上有一定的局限性. ...

  6. Word/WPS 利用邮件合并批量生成文档

    Word/WPS 利用邮件合并批量生成文档 WPS 1. 先找到功能所有位置 2. 准备用于批量生成的数据 3. 插入数据批量生成文档 4. 批量生成文档 插入Next 域 Word 第1步,选择文档 ...

  7. staruml画的图怎么加载到word_StarUML配置Word生成文档模板

    许多UML建模工具可以自动生成文档,让需求人员.开发人员专心于需求.设计的建模.当然为了能够生成符合自己要求的模板,需对建模时的目录结构(模型和包)有所规划和要求,否则很难生成相应的文档.这要求提前了 ...

  8. oracle导出pdm文件命令,利用PowerDesigner逆向工程导出PDM模型及生成文档

    最近需要对老项目进行重构优化,由于项目都是好几年前的,相关设计资料很不全,最基本的数据库设计文档都没有,只能利用PowerDesigner逆向工程导出PDM模型及生成word文档:以下简单介绍导出模型 ...

  9. python怎么自动生成文档_用 Python 自动生成 Word 文档

    当然要用第三方库啦 :) 使用以下命令安装: pip install  python-docx 使用该库的基本步骤为: 1.建立一个文档对象(可自动使用默认模板建立,也可以使用已有文件). 2.设置文 ...

最新文章

  1. php错误密码也能登陆账号,php用户登陆代码(限制用户错误登录次数)(1/2
  2. matlab和C如何混编
  3. 如何打造千万级Feed流系统?阿里数据库技术解读
  4. highcharts 显示网格
  5. 顶级Javaer,常用的 14 个类库
  6. 【转】xPath语法介绍
  7. Linux 系统中的超级权限的控制
  8. 17 张程序员专属壁纸,太太太太太太骚了…
  9. DSP程序中 ,如何完成延时且不影响整体程序的工作效率
  10. 令牌环桶算法的使用案例
  11. excel函数去重_excel去重函数
  12. suse12 sp4,sp5镜像资源分享
  13. wps2005插件开发之旅
  14. 西门子1200PLC(入门)2
  15. 记录一下 MacBook 中 texlive 的安装路径
  16. 量子信息与量子计算_我们会看到量子计算革命吗?
  17. 九联UNT403G/UNT413G_国科GK6323芯片_5621ds无线wifi_免拆卡刷固件
  18. Vue笔记(适合后端人员开发的快速入门)
  19. Axure学习笔记(三)——交互事件设置
  20. Zookeeper 安装配置(大数据工程师工作笔记)

热门文章

  1. 7-1 ysu小吃街 (100分)【思路超级简单的版本】
  2. 青云QingCloud助力掌众金服挖掘数据价值
  3. 微信美食菜谱小程序系统设计与实现
  4. tinymce_2_1_2汉化方法
  5. [2020-01-01] 树莓派 4B+ 安装笔记
  6. java 向上、向下取整,四舍五入
  7. SAP 如何连接外部数据库
  8. 解决android studio模拟器不显示应用问题
  9. 在matlab中dt什么意思,matlab中的 fixdt是什么意思
  10. 照片调色系列教程(6):唯美婚纱效果