Некорректно разделяется docx файл
Нужно вставить содержимое файла for_copy_path в файл template_path в строчку где написано {{ FOR_PASTE }}. В обоих файлах находиться необходимое форматирование, которое нужно сохранить.
Перепробовал кучу вариантов, из которых остановился на разделение docx файла на два в нужном месте (где {{ FOR_PASTE }}) и вставкой другого файла между ними с помощью docxcompose.composer. Но колонтитулы в файле template_path плывут и добавляются некорректно.
import tempfile
from typing import Generator, Tuple
from docx import Document
from docx.document import Document as DocType
from docx.oxml.text.paragraph import CT_P
from docx.oxml.xmlchemy import BaseOxmlElement
from docx.text.paragraph import Paragraph
from docxcompose.composer import Composer
template_path = r'Dockx\\shablon.docx'
output_path1 = r'Dockx\\result1.docx'
output_path2 = r'Dockx\\result2.docx'
for_copy_path = r'Dockx\\text_for_copy.docx'
output_path = r'Dockx\\result.docx'
def iterparts(doc_path: str, split_text: str) -> Generator[Tuple[int, DocType], None, None]:
"""Iterate over sub-documents by splitting source document into parts."""
doc = Document(doc_path)
split_elem_idx = -1
doc_body = doc.element.body
for idx, elem in enumerate(doc_body.iterchildren()):
if is_split_point(elem, split_text):
split_elem_idx = idx
break
if split_elem_idx != -1:
yield split(doc, split_elem_idx)
else:
yield (doc, None)
def is_split_point(element: BaseOxmlElement, split_text: str) -> bool:
"""Check if the element is the split point."""
if isinstance(element, CT_P):
p = Paragraph(element, element.getparent())
return split_text in p.text
return False
def split(doc: DocType, cut_idx: int) -> Tuple[DocType, DocType]:
"""Split the document into two parts at the given index."""
tmpdocfile = write_tmp_doc(doc)
second_part = doc
second_elems = list(second_part.element.body.iterchildren())
for i in range(0, cut_idx + 1):
remove_element(second_elems[i])
first_part = Document(tmpdocfile)
first_elems = list(first_part.element.body.iterchildren())
for i in range(cut_idx, len(first_elems)):
remove_element(first_elems[i])
tmpdocfile.close()
return (first_part, second_part)
def write_tmp_doc(doc: DocType) -> tempfile.NamedTemporaryFile:
"""Write the document to a temporary file."""
tmpfile = tempfile.NamedTemporaryFile(delete=False)
doc.save(tmpfile.name)
return tmpfile
def remove_element(elem):
"""Remove an element from its parent."""
parent = elem.getparent()
parent.remove(elem)
def save_doc_parts(template_path: str, split_text: str):
parts = list(iterparts(template_path, split_text))
if parts:
first_part, second_part = parts[0]
if first_part:
first_part.save(output_path1)
if second_part:
second_part.save(output_path2)
# Открытие документов
template1 = Document(output_path1)
template2 = Document(output_path2)
for_copy = Document(for_copy_path)
# Создание композитного документа
composer = Composer(template1)
composer.append(for_copy)
composer.append(template2)
# Сохранение результата
composer.save(output_path)
# Вызов основной функции
save_doc_parts(template_path, "{{ FOR_PASTE }}")
Файлы: https://drive.google.com/file/d/1mXuKeaW7phb3iWWZ7QDZJRv_G-W406KY/view
Вот как плывёт колонтитул (слева шаблон, справа результат):