fix: сохранять разрыв страницы (w:br type=page) при развороте циклов

Word хранит перенос страницы отдельным run в параграфе с <!-- loop_end -->.
Нормализация раньше удаляла его при склейке текста — акты слипались.
Теперь page break сохраняется и копируется в каждую итерацию цикла.
Проверено: 2 ИС -> 2 разрыва страниц, XML валиден.
This commit is contained in:
2026-08-03 10:29:10 +04:00
parent f4306f130e
commit 65480ea5ed
+21
View File
@@ -93,6 +93,12 @@ def _normalize_loop_markers(doc_xml: str) -> str:
if '{{' not in full and 'loop:' not in full and 'loop_end' not in full:
continue
# Был ли в параграфе разрыв страницы (Word хранит его отдельным run)
has_page_break = any(
br.get(f'{{{W_NS}}}type') == 'page'
for br in p.iter(f'{{{W_NS}}}br')
)
# Сохраняем форматирование первого run
first_r = p.find(f'{{{W_NS}}}r')
rpr = None
@@ -106,6 +112,14 @@ def _normalize_loop_markers(doc_xml: str) -> str:
if child.tag != f'{{{W_NS}}}pPr':
p.remove(child)
# Разрыв страницы — отдельным run ПЕРЕД текстом (как было в оригинале)
if has_page_break:
br_r = etree.SubElement(p, f'{{{W_NS}}}r')
if rpr is not None:
br_r.append(etree.fromstring(etree.tostring(rpr)))
br_el = etree.SubElement(br_r, f'{{{W_NS}}}br')
br_el.set(f'{{{W_NS}}}type', 'page')
# Создаём один run с полным текстом параграфа
new_r = etree.SubElement(p, f'{{{W_NS}}}r')
if rpr is not None:
@@ -204,6 +218,12 @@ def expand_loops_in_zip(docx_path: str, loops: Dict[str, List[Dict]]) -> str:
wrote = True
continue
# Разрыв страницы рядом с маркером конца цикла (Word хранит его
# отдельным run в параграфе с <!-- loop_end -->). Если он есть —
# каждый акт/блок цикла должен начинаться с новой страницы.
probe = doc_xml[max(0, outer_end.start() - 800):outer_end.end()]
has_page_break = '<w:br w:type="page"/>' in probe
# Извлекаем шаблон (всё между start и end маркерами)
template = doc_xml[outer.end():outer_end.start()]
@@ -224,6 +244,7 @@ def expand_loops_in_zip(docx_path: str, loops: Dict[str, List[Dict]]) -> str:
clone = clone.replace('{{number}}', str(idx))
expanded_parts.append(clone)
# Собираем новый XML
new_xml = doc_xml[:outer.start()] + ''.join(expanded_parts) + doc_xml[outer_end.end():]