我记得一个老谚语:“使用源代码,卢克!” ,所以我能够想通。来自python-docx所有者在其git项目页面上的一篇文章也给了我一个提示:https://github.com/python-openxml/python-docx/issues/7。
完整的XML文档模型可以通过使用其_document_part._element
属性来访问。它的行为就像一个lxml etree元素。从那里,一切皆有可能。
为了解决我特定的插入点问题,我创建了一个临时的docx.Document对象,用于存储我的生成内容。
import docx
from docx.oxml.shared import qn
tmp_doc = docx.Document()
tmp_doc.add_heading('New heading', 1)
tmp_doc_body = tmp_doc._document_part._element.body
然后我将包含名为 'insertion_point' 的书签的docx模板加载到第二个docx.Document对象中。
doc = docx.Document('/some/path/example.docx')
doc_body = doc._document_part._element.body
下一步是解析doc XML以查找插入点的索引。我为此任务定义了一个小函数,它返回一个带名称的书签父段落元素:
接下来要解析文档XML文件以查找插入点的索引。我为这个任务定义了一个小函数,该函数返回一个命名的书签父段落元素:
def get_bookmark_par_element(document, bookmark_name):
"""
Return the named bookmark parent paragraph element. If no matching
bookmark is found, the result is '1'. If an error is encountered, '2'
is returned.
"""
doc_element = document._document_part._element
bookmarks_list = doc_element.findall('.//' + qn('w:bookmarkStart'))
for bookmark in bookmarks_list:
name = bookmark.get(qn('w:name'))
if name == bookmark_name:
par = bookmark.getparent()
if not isinstance(par, docx.oxml.CT_P):
return 2
else:
return par
return 1
新定义的函数被用来获取书签“insertion_point”的父段落。错误控制留给读者自行处理。
bookmark_par = get_bookmark_par_element(doc, 'insertion_point')
我们现在可以使用 bookmark_par 的 etree 索引,在正确的位置插入我们生成的 tmp_doc 内容:
bookmark_par_parent = bookmark_par.getparent()
index = bookmark_par_parent.index(bookmark_par) + 1
for child in tmp_doc_body:
bookmark_par_parent.insert(index, child)
index = index + 1
bookmark_par_parent.remove(bookmark_par)
该文档现已定稿,生成的内容已插入到现有Word文档中书签位置。
doc.save('/some/path/generated_doc.docx')
我希望这能帮到某些人,因为关于这个的文档还没有被编写。
doc_element = doc.part.element
而不是doc_element = document._document_part._element
。 - Max