为什么用 Python 批量处理 Word 域
Word 域由域代码和域结果组成,页脚页码、目录页码、章节引用、条件文本都可以通过域动态更新。手动在 Word 中写域代码,再逐个更新几十个域,维护成本很高。用 Python 和 Spire.Doc for Python 可以批量插入域、更新域结果、读取 FieldText、把域转成普通文本以及删除域。
环境准备:- from spire.doc import *
- from spire.doc.common import *
复制代码
用 AppendField 插入简单域
Paragraph.AppendField() 可在段落末尾插入指定类型的域。第一个参数是显示文本,第二个参数是 FieldType 枚举;FieldType.FieldNone 表示空域,FieldPageRef、FieldMergeField 等对应具体类型。插入后设置 Field.Code,等价于手动输入域代码。下面示例插入 PageRef 域并引用书签 bookmark1:- document = Document()
- document.LoadFromFile('文档.docx')
- # 获取最后一个节并新建一个段落
- section = document.LastSection
- par = section.AddParagraph()
- # 插入 PageRef 域并设置域代码
- field = par.AppendField('pageRef', FieldType.FieldPageRef)
- field.Code = 'PAGEREF bookmark1 \\# "0" \\* Arabic \\* MERGEFORMAT'
- # 更新域以获得正确的结果
- document.IsUpdateFields = True
- document.SaveToFile('插入域.docx', FileFormat.Docx)
- document.Close()
复制代码 注意:field.Code 中的反斜杠是 Word 域开关的一部分,示例用单引号包裹 Python 字符串,因此内部双引号可以保留。
构造带条件的 IF 域
IF 域适合动态判断。IfField 是 Field 的子类,需要先加入段落 Items,再拼装条件、真值、假值,最后补 FieldMarkType.FieldEnd 结束标记并关联 End 属性。示例用邮件合并字段 Count 判断数量是否大于 100:- def create_if_field(document, paragraph):
- if_field = IfField(document)
- if_field.Type = FieldType.FieldIf
- if_field.Code = 'IF '
- paragraph.Items.Add(if_field)
- # 条件:合并字段 Count 的值大于 100
- paragraph.AppendField('Count', FieldType.FieldMergeField)
- paragraph.AppendText(' > ')
- paragraph.AppendText('"100" ')
- # 真值和假值
- paragraph.AppendText('"Thanks" ')
- paragraph.AppendText('"The minimum order is 100 units"')
- # 添加域结束标记
- end = document.CreateParagraphItem(ParagraphItemType.FieldMark)
- end.Type = FieldMarkType.FieldEnd
- paragraph.Items.Add(end)
- if_field.End = end
- document = Document()
- section = document.AddSection()
- paragraph = section.AddParagraph()
- create_if_field(document, paragraph)
- # 用邮件合并数据填充 Count 字段
- document.MailMerge.Execute(['Count'], ['2'])
- # 更新所有域
- document.IsUpdateFields = True
- document.SaveToFile('IF域.docx', FileFormat.Docx2013)
- document.Close()
复制代码 IF 域条件部分要按“表达式 + 比较符 + 值”的顺序拼装,文本值必须用英文双引号包住。MailMerge.Execute() 负责把 Count 的实际值写入文档,保存时 IsUpdateFields 触发重新计算,从而得到不同真假分支结果。
统一更新文档中的所有域
域显示的是最后一次计算的结果。如果文档由程序动态生成,或者数据源发生变化,保存前应设置 IsUpdateFields:- document = Document()
- document.LoadFromFile('文档.docx')
- # 保存前更新所有域
- document.IsUpdateFields = True
- document.SaveToFile('更新域.docx', FileFormat.Docx)
- document.Close()
复制代码 IsUpdateFields 必须放在 SaveToFile() 之前,否则保存结果里的域不会重新计算。
读取域中的文本
Document.Fields 返回全部域的集合,FieldText 暴露当前计算出的文本。遍历集合可以快速检查域是否生效:- document = Document()
- document.LoadFromFile('文档.docx')
- fields = document.Fields
- for i in range(fields.Count):
- field = fields.get_Item(i)
- print(field.FieldText)
- document.Close()
复制代码 也可以按索引访问,例如 fields[0] 取第一个域。
把域转换为普通文本
文档定稿、导出订单或合同给客户时,如果不想让域继续动态更新,可以把域结果转成普通文本。思路是读取 FieldText,在域所在段落的位置插入 TextRange,再移除原域对象:- document = Document()
- document.LoadFromFile('文档.docx')
- fields = document.Fields
- count = fields.Count
- for i in range(0, count):
- field = fields[0]
- s = field.FieldText
- index = field.OwnerParagraph.ChildObjects.IndexOf(field)
- text_range = TextRange(document)
- text_range.Text = s
- text_range.CharacterFormat.FontSize = 24
- # 用文本替换域的位置,再移除域
- field.OwnerParagraph.ChildObjects.Insert(index, text_range)
- field.OwnerParagraph.ChildObjects.Remove(field)
- document.SaveToFile('域转文本.docx', FileFormat.Docx)
- document.Close()
复制代码 循环中每次处理 fields[0],因为每移除一个域,fields.Count 会变化。域转文本会丢失动态特性,适合对外分发前的定稿处理;如果文档还要在内部流转,建议保留域。
删除不需要的域
删除域时,先取域对象,再通过 OwnerParagraph 找到所属段落,用 ChildObjects.IndexOf() 定位下标,最后 RemoveAt() 删除:- document = Document()
- document.LoadFromFile('文档.docx')
- # 获取第一个域及其所在段落
- field = document.Fields[0]
- par = field.OwnerParagraph
- # 定位域在段落中的位置并删除
- index = par.ChildObjects.IndexOf(field)
- par.ChildObjects.RemoveAt(index)
- document.SaveToFile('删除域.docx', FileFormat.Docx)
- document.Close()
复制代码 批量删除时,把上述定位和删除逻辑放进循环即可。
实用提示
1. 在 Word 中按 Alt+F9 可切换域代码显示,生成后建议确认关键域代码格式。
2. IsUpdateFields 要在 SaveToFile() 之前设置。
3. IF 域条件严格按表达式、比较符、值的顺序拼装,文本值用英文双引号。
4. 域转文本适合定稿或对外分发,内部流转保留域更灵活。
5. 处理完文档调用 document.Close() 释放资源。
总结
本文围绕 Spire.Doc for Python 演示了 Word 域操作的完整流程:AppendField() 插入简单域,IfField 构造条件域,IsUpdateFields 统一更新,Document.Fields 读取 FieldText,通过 TextRange 把域转普通文本,以及用 OwnerParagraph、ChildObjects、IndexOf()、RemoveAt() 删除域。这些方法可以覆盖页码、条件判断、邮件合并数据等动态文档场景。 |