Tôi nhớ một câu ngạn ngữ cũ, "sử dụng nguồn, Luke!", Và có thể tìm ra. Một bài đăng từ chủ sở hữu python-docx trên trang dự án git của nó cũng cho tôi một gợi ý: https://github.com/python-openxml/python-docx/issues/7.
Mô hình tài liệu XML đầy đủ có thể được truy cập bằng cách sử dụng thuộc tính _document_part._element
của nó. Nó hoạt động chính xác như một phần tử lxml etree. Từ đó, mọi thứ đều có thể.
Để giải quyết vấn đề điểm chèn cụ thể của tôi, tôi đã tạo đối tượng docx.Document tạm thời mà tôi đã sử dụng để lưu trữ nội dung đã tạo của mình.
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))
Sau đó, tôi đã tải mẫu docx của mình (chứa dấu trang có tên 'insertion_point') vào đối tượng docx.Document thứ hai.
doc = docx.Document('/some/path/example.docx')
doc_body = doc._document_part._element.body
#print(docx.oxml.xmlchemy.serialize_for_reading(doc_body))
Bước tiếp theo là phân tích cú pháp XML để tìm chỉ mục của điểm chèn. Tôi định nghĩa một hàm nhỏ cho các nhiệm vụ trong tầm tay, mà trả về một yếu tố đoạn mẹ bookmark tên:
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
Chức năng mới định nghĩa được sử dụng toget bookmark 'insertion_point' đoạn mẹ. Kiểm soát lỗi được để lại cho người đọc.
bookmark_par = get_bookmark_par_element(doc, 'insertion_point')
Bây giờ chúng ta có thể sử dụng chỉ số etree bookmark_par để chèn tmp_doc của chúng tôi tạo ra nội dung ở đúng nơi:
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)
Tài liệu này hiện đang hoàn thiện, nội dung được tạo ra sau khi được chèn vào vị trí đánh dấu của một tài liệu Word hiện có.
# Save result
# print(docx.oxml.xmlchemy.serialize_for_reading(doc_body))
doc.save('/some/path/generated_doc.docx')
Tôi hy vọng điều này có thể giúp ai đó, vì tài liệu liên quan đến vấn đề này vẫn chưa được viết.
Cảm ơn đã chia sẻ! Tôi không cần phải thử nghiệm với hình ảnh, vì vậy tôi không chắc chắn về những thách thức ở phía đó. – Apteryx