Точка вставки python-docx

Вопрос:Я не уверен, что я упустил что-то очевидное, но я не нашел ничего документированного о том, как можно было бы вставлять элементы Word (например, таблицы) в определенное место в документе? Я загружаю существующий документ MS Word.docx, используя: my_document = Document('some/path/to/my/document.docx') Моим вариантом использования было бы получить "позицию" закладки или раздела в документе, а затем перейти

Вопрос:

Я не уверен, что я упустил что-то очевидное, но я не нашел ничего документированного о том, как можно было бы вставлять элементы Word (например, таблицы) в определенное место в документе?

Я загружаю существующий документ MS Word.docx, используя:

my_document = Document(‘some/path/to/my/document.docx’)

Моим вариантом использования было бы получить “позицию” закладки или раздела в документе, а затем перейти к вставке таблиц ниже этой точки.

Я думаю об API, который позволил бы мне что-то делать по этим строкам:

insertion_point = my_document.bookmarks[‘bookmark_name’].position my_document.add_table(rows=10, cols=3, position=insertion_point+1)

Я видел, что есть планы реализовать что-то похожее на “диапазон” объекта MS Word API, это эффективно решает эту проблему. Между тем, существует ли способ проинструктировать методы объекта document, где нужно вставлять новые элементы?

Может быть, я могу приклеить некоторый код lxml, чтобы найти node и передать это этим методам python-docx? Любая помощь по этому вопросу была бы высоко оценена! Спасибо.

Лучший ответ:

Я вспомнил старую пословицу, “используйте источник, Люк!”, и мог понять это. Сообщение от владельца python-docx на странице проекта git также дало мне подсказку: https://github.com/python-openxml/python-docx/issues/7.

Доступ к полной модели документа XML можно получить с помощью свойства _document_part._element. Он ведет себя точно так же, как элемент lxml etree. Оттуда все возможно.

Чтобы решить мою конкретную проблему с вставкой, я создал объект temp 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-документа doc, чтобы найти индекс точки вставки. Я определил небольшую функцию для задачи, которая возвращает элемент абзаца родительского элемента с именем:

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’)

Теперь мы можем использовать index_par etree index для вставки нашего сгенерированного содержимого 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’)

Надеюсь, это поможет кому-то, поскольку документация по этому поводу еще не написана.

Ответ №1

Владелец Python-docx предлагает, как вставить таблицу в середину существующего документа:
https://github.com/python-openxml/python-docx/issues/156

Вот некоторые улучшения:

import re from docx import Document def move_table_after(document, table, search_phrase): regexp = re.compile(search_phrase) for paragraph in document.paragraphs: if paragraph.text and regexp.search(paragraph.text): tbl, p = table._tbl, paragraph._p p.addnext(tbl) return paragraph if __name__ == ‘__main__’: document = Document(‘Existing_Document.docx’) table = document.add_table(rows=…, cols=…) … move_table_after(document, table, «your search phrase») document.save(‘Modified_Document.docx’) Ответ №2

Спасибо, что нашли время, чтобы объяснить все это.

Я пережил более или менее ту же проблему. Моя особая точка заключалась в том, как объединить два или более документа docx в конце.

Это не совсем решение вашей проблемы, но вот функция, с которой я пришел:

def combinate_word(main_file, files, output): main_doc = Document(main_file) for file in files: sub_doc = Document(file) for element in sub_doc._document_part.body._element: main_doc._document_part.body._element.append(element) main_doc.save(output)

К сожалению, пока невозможно скопировать изображения с помощью python-docx. Я возвращаюсь к win32com…

Ответ №3

Вы помещаете [изображение] в качестве токена в документе шаблона:

for paragraph in document.paragraphs: if «[image]» in paragraph.text: paragraph.text = paragraph.text.strip().replace(«[image]», «») run = paragraph.add_run() run.add_picture(image_path, width=Inches(3))

у вас есть параграф в ячейке таблицы. просто найдите ячейку и выполните действия, описанные выше.

Ответ №4

Взгляните на python-docx-template, который позволяет вставлять шаблоны стиля jinja2 в файл docx, а не в закладки Word:

https://pypi.org/project/docxtpl/

https://docxtpl.readthedocs.io/en/latest/

Оцените статью
Добавить комментарий