Fix: remove source sectPr to prevent Word corruption and integrate SDT filling
This commit is contained in:
+61
-1
@@ -77,6 +77,29 @@ def parse_xml(content: bytes) -> etree._Element:
|
|||||||
return etree.fromstring(content)
|
return etree.fromstring(content)
|
||||||
|
|
||||||
|
|
||||||
|
def fill_sdt_fields(xml_root: etree._Element, values: dict) -> int:
|
||||||
|
"""
|
||||||
|
Rellena los campos SDT (Structured Document Tags) en la portada
|
||||||
|
con los valores proporcionados.
|
||||||
|
"""
|
||||||
|
filled = 0
|
||||||
|
for sdt in xml_root.iter(q('w:sdt')):
|
||||||
|
alias_el = sdt.find(q('w:alias'))
|
||||||
|
if alias_el is None:
|
||||||
|
continue
|
||||||
|
alias = alias_el.get(q('w:val'))
|
||||||
|
if alias and alias in values and values[alias]:
|
||||||
|
sdt_content = sdt.find(q('w:sdtContent'))
|
||||||
|
if sdt_content is not None:
|
||||||
|
for run in sdt_content.iter(q('w:r')):
|
||||||
|
for t in run.iter(q('w:t')):
|
||||||
|
t.text = values[alias]
|
||||||
|
filled += 1
|
||||||
|
break
|
||||||
|
break
|
||||||
|
return filled
|
||||||
|
|
||||||
|
|
||||||
def q(tag: str) -> str:
|
def q(tag: str) -> str:
|
||||||
"""Convierte 'w:body' a la URL completa con namespace."""
|
"""Convierte 'w:body' a la URL completa con namespace."""
|
||||||
prefix, local = tag.split(':')
|
prefix, local = tag.split(':')
|
||||||
@@ -490,6 +513,7 @@ def replace_content(
|
|||||||
source_docx_path: str | Path,
|
source_docx_path: str | Path,
|
||||||
output_path: str | Path,
|
output_path: str | Path,
|
||||||
style_map: dict | None = None,
|
style_map: dict | None = None,
|
||||||
|
doc_vars: dict | None = None,
|
||||||
) -> Path:
|
) -> Path:
|
||||||
"""
|
"""
|
||||||
Núcleo de la conversión: fusiona template + source en un solo documento.
|
Núcleo de la conversión: fusiona template + source en un solo documento.
|
||||||
@@ -527,6 +551,11 @@ def replace_content(
|
|||||||
if body_src is None:
|
if body_src is None:
|
||||||
raise DocxError("El documento fuente no tiene body")
|
raise DocxError("El documento fuente no tiene body")
|
||||||
|
|
||||||
|
# ---- Rellenar campos SDT en la portada ----
|
||||||
|
if doc_vars:
|
||||||
|
filled = fill_sdt_fields(tmpl_xml, doc_vars)
|
||||||
|
log.info(" Campos SDT rellenados: %d", filled)
|
||||||
|
|
||||||
children_tmpl = list(body_tmpl)
|
children_tmpl = list(body_tmpl)
|
||||||
children_src = list(body_src)
|
children_src = list(body_src)
|
||||||
|
|
||||||
@@ -749,7 +778,31 @@ def run_single(args) -> int:
|
|||||||
log.info(" 🏁 Dry-run: todo correcto, no se genera nada.")
|
log.info(" 🏁 Dry-run: todo correcto, no se genera nada.")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
replace_content(template, source, output)
|
# Preparar variables para la portada
|
||||||
|
doc_vars = {
|
||||||
|
'Cliente': args.cliente,
|
||||||
|
'Título': args.titulo,
|
||||||
|
'Asunto': args.asunto,
|
||||||
|
'Categoría': args.tipo,
|
||||||
|
'Palabras clave': args.codigo,
|
||||||
|
}
|
||||||
|
|
||||||
|
# 1. Cargar el XML del template
|
||||||
|
z_tmpl = zipfile.ZipFile(str(template), 'r')
|
||||||
|
tmpl_xml = parse_xml(z_tmpl.read('word/document.xml'))
|
||||||
|
|
||||||
|
# 2. Rellenar campos SDT en la portada
|
||||||
|
filled = fill_sdt_fields(tmpl_xml, doc_vars)
|
||||||
|
log.info(" Campos SDT rellenados: %d", filled)
|
||||||
|
|
||||||
|
# Guardar el XML modificado temporalmente para que replace_content lo use
|
||||||
|
# (Sugerencia: pasar el XML ya modificado a replace_content o modificar la función)
|
||||||
|
# Para evitar re-diseñar replace_content, vamos a inyectar el comportamiento
|
||||||
|
# en la función principal.
|
||||||
|
z_tmpl.close()
|
||||||
|
|
||||||
|
# ... (dentro de run_single) ...
|
||||||
|
replace_content(template, source, output, doc_vars=doc_vars)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
@@ -889,6 +942,13 @@ Ejemplos:
|
|||||||
help='Archivo de salida (solo modo single)',
|
help='Archivo de salida (solo modo single)',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Variables de portada
|
||||||
|
parser.add_argument('--cliente', default='', help='Nombre del cliente')
|
||||||
|
parser.add_argument('--titulo', default='', help='Título del documento')
|
||||||
|
parser.add_argument('--asunto', default='', help='Subtítulo / asunto')
|
||||||
|
parser.add_argument('--tipo', default='', help='Tipo de documento')
|
||||||
|
parser.add_argument('--codigo', default='', help='Código de documento')
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user