我想起了一句古老的格言,“使用来源,卢克!”,并且可以理解。python-docx 所有者在其 git 项目页面上的帖子也给了我一个提示:https ://github.com/python-openxml/python-docx/issues/7 。
可以使用其_document_part._element
属性访问完整的 XML 文档模型。它的行为与 lxml etree 元素完全一样。从那里开始,一切皆有可能。
为了解决我的特定插入点问题,我创建了一个临时 docx.Document 对象,用于存储我生成的内容。
import docx
from docx.oxml.shared import qn
tmp_doc = docx.Document()
# Generate content in tmp_doc document
tmp_doc.add_heading('New heading', 1)
# more content generation using docx API.
# ...
# Reference the tmp_doc XML content
tmp_doc_body = tmp_doc._document_part._element.body
# You could pretty print it by using:
#print(docx.oxml.xmlchemy.serialize_for_reading(tmp_doc_body))
然后我将我的 docx 模板(包含一个名为“insertion_point”的书签)加载到第二个 docx.Document 对象中。
doc = docx.Document('/some/path/example.docx')
doc_body = doc._document_part._element.body
#print(docx.oxml.xmlchemy.serialize_for_reading(doc_body))
下一步是解析文档 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 文档的书签位置。
# Save result
# print(docx.oxml.xmlchemy.serialize_for_reading(doc_body))
doc.save('/some/path/generated_doc.docx')
我希望这可以帮助某人,因为有关此的文档仍未编写。