「ソースを使え、ルーク!」という古い格言を思い出し、それを理解することができました。git プロジェクト ページの python-docx 所有者からの投稿もヒントを与えてくれました: 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」という名前のブックマークを含む) を 2 つ目の 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))
次のステップは、doc 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')
これに関するドキュメントはまだ作成されていないため、これが誰かの助けになることを願っています。