大家好 . 我会尽量简单明了 . :)
I have
-
40个左右的样板文字文件,包含一系列需要填写的字段(名称,地址等) . 这在历史上是手工完成的,但它是重复和繁琐的 .
-
用户填写了大量有关个人信息的工作簿 .
I need
- 一种以编程方式(从Excel VBA)打开这些样板文档的方法,编辑工作簿中各种命名范围的字段值,并将填充的模板保存到本地文件夹 .
如果我使用VBA以编程方式编辑一组电子表格中的特定值,我会编辑所有这些电子表格以包含一组可在自动填充过程中使用的命名范围,但我不知道任何'命名Word文档中的字段'功能 .
我如何编辑文档,并创建一个VBA例程,以便我可以打开每个文档,查找可能需要填写的一组字段,并替换值?
例如,某些东西的作用如下:
for each document in set_of_templates
if document.FieldExists("Name") then document.Field("Name").value = strName
if document.FieldExists("Address") then document.Field("Name").value = strAddress
...
document.saveAs( thisWorkbook.Path & "\GeneratedDocs\ " & document.Name )
next document
我考虑过的事情:
-
邮件合并 - 但这是不够的,因为它需要手动打开每个文档并将工作簿构造为数据源,我有点想要相反 . 模板是数据源,工作簿正在迭代它们 . 此外,邮件合并用于使用不同数据的表创建许多相同的文档 . 我有很多文件都使用相同的数据 .
-
使用占位符文本(如"#NAME#")并打开每个文档进行搜索和替换 . 如果没有提出更优雅的话,我会采用这个解决方案 .
4 回答
自从我提出这个问题以来已经有很长一段时间了,我的解决方案经历了越来越多的改进 . 我不得不处理各种特殊情况,例如直接来自工作簿的值,需要根据列表专门生成的部分,以及需要在页眉和页脚中进行替换 .
事实证明,使用书签是不够的,因为用户以后可以编辑文档来更改,添加和删除文档中的占位符值 . 解决方案实际上是使用 keywords ,例如:
这只是一个示例文档中的页面,它使用了一些可以自动插入到文档中的可能值 . 存在超过50个具有完全不同的结构和布局并使用不同参数的文档 . word文档和excel电子表格共享的唯一常识是了解这些占位符值的含义 . 在excel中,它存储在文档生成关键字列表中,其中包含关键字,后跟对实际包含此值的范围的引用:
这些是所需的关键两种成分 . 现在有了一些聪明的代码,我所要做的就是遍历要生成的每个文档,然后迭代所有已知关键字的范围,并对每个文档中的每个关键字进行搜索和替换 .
首先,我有一个包装器方法,它负责维护一个微软单词的实例迭代所有选择用于生成的文档,编号文档和执行用户界面的东西(如处理错误,向用户显示文件夹等) . )
该例程调用
RunReplacements
,负责打开文档,准备快速替换环境,更新链接,处理错误等:该例程然后调用
RunSimpleReplacements
. 和RunAdvancedReplacements
. 在前者中,我们迭代文档生成关键字集并在文档包含我们的关键字时调用WordDocReplace
. 请注意,尝试使用Find
一堆字来判断它们不存在然后不加选择地调用replace会快得多,所以我们总是在尝试替换之前检查关键字是否存在 .这是用于检测文档中是否存在关键字的函数:
这就是橡胶遇到道路的地方 - 执行更换的代码 . 当我遇到困难时,这个程序变得更加复杂 . 以下是您只能从经验中学到的课程:
您可以直接设置替换文本,也可以使用剪贴板 . 我发现了一个很难的方法,如果你正在进行VBA取代使用长度超过255个字符的字符串,如果您尝试将文本放在_3030869中,文本将被截断,但您可以使用
"^c"
作为替换文本,它将直接从剪贴板获取 . 这是我使用的解决方法 .简单地调用replace会在页眉和页脚等文本区域中遗漏关键字 . 因此,您实际上需要遍历
document.StoryRanges
并运行搜索并替换每一个以确保捕获要替换的单词的所有实例 .如果您直接设置
Replacement.Text
,则需要使用简单的vbCr
转换Excel换行符(vbNewLine
和Chr(10)
),以使它们在单词中正确显示 . 否则,在替换文本中有来自excel单元格的换行符的任何地方最终会将奇怪的符号插入到单词中 . 但是,如果使用剪贴板方法,则不需要执行此操作,因为换行符在放入剪贴板时会自动转换 .这解释了一切 . 评论也应该很清楚 . 这是执行魔术的黄金例程:
当尘埃落定时,我们留下了一个漂亮的初始文档版本,其中 生产环境 值代替那些散列标记的关键字 . 我想展示一个例子,但当然每个填写的文档都包含所有专有信息 .
我想的唯一想法是
RunAdvancedReplacements
部分 . 它做了类似的事情 - 它最终调用相同的WordDocReplace
函数,但是's special about the keywords used here is that they don't链接到原始工作簿中的单个单元格,它们是从工作簿中的列表中的代码隐藏生成的 . 因此,例如,其中一个高级替换将如下所示:然后会有一个相应的例程,它将包含用户配置的所有血管信息的字符串组合在一起:
生成的字符串可以像任何excel单元格的内容一样使用,并传递给替换函数,如果超过255个字符,它将适当地使用剪贴板方法 .
So this template:
Plus this spreadsheet data:
Becomes this document:
我真诚地希望有一天能帮助某人 . 这绝对是一项艰巨的任务,也是一个必须重新发明的复杂轮子 . 应用程序非常庞大,有超过50,000行的VBA代码,所以如果我在我的代码中引用某个人需要的关键方法,请发表评论,我会在这里添加它 .
http://www.computorcompanion.com/LPMArticle.asp?ID=224描述使用Word bookmarks
可以为文档中的一段文本添加书签,并为其指定变量名称 . 使用VBA,可以访问此变量,并且可以使用备用内容替换文档中的内容 . 这是在文档中使用名称和地址等占位符的解决方案 .
此外,使用书签,可以修改文档以引用书签文本 . 如果名称在整个文档中多次出现,则第一个实例可以加入书签,其他实例可以引用该书签 . 现在,当以编程方式更改第一个实例时,整个文档中变量的所有其他实例也会自动更改 .
现在所需要的只是通过为占位符文本添加书签并在整个文档中使用一致的命名约定来更新所有文档,然后遍历每个文档,替换书签(如果存在):
在尝试每次替换之前,我可以使用on error resume next子句解决在给定文档中没有出现的变量问题 .
感谢Doug Glancy在他的评论中提到了书签的存在 . 我事先并不知道他们的存在 . 我会在这个主题是否满足时发布这个主题 .
您可以考虑使用基于XML的方法 .
Word具有称为自定义XML数据绑定或数据绑定内容控件的功能 . 内容控件本质上是文档中可以包含内容的一个点 . “数据绑定”内容控件从您包含在docx zip文件中的XML文档中获取其内容 . XPath表达式用于表示XML的哪个位 . 所以你需要做的就是包含你的XML文件,Word将完成剩下的工作 .
Excel有办法从XML中获取数据,因此整个解决方案应该可以很好地工作 .
有关MSDN上内容控制数据绑定的大量信息(其中一些已在早期的SO问题中引用)我不会在这里包括他们 .
但是你确实需要一种设置绑定的方法 . 您可以使用Content Control Toolkit,或者如果您想在Word,我的OpenDoPE插件中执行此操作 .
完成类似的任务后,我发现在表中插入值要比搜索命名标签快得多 - 然后可以像这样插入数据:
.Cell(i 1,4).Range.Text =“Total:”End在这种情况下,表格的第1行是 Headers ;第2行是空的,没有其他行 - 因此rows.add仅在连接一行时应用 . 表格可以是非常详细的文档,通过隐藏边框和单元格边框可以看起来像普通文本 . 表格按文件流程顺序编号 . (即Doc.Tables(1)是第一个表......