From df9e895b2be5a46317d7d312c2c9f4ae61b9d90e Mon Sep 17 00:00:00 2001 From: zxyasfas <138371657+zxyasfas@users.noreply.github.com> Date: Wed, 29 Jul 2026 15:18:37 +0800 Subject: [PATCH] Expand self-closing tcPr before inserting gridSpan and shd --- docxtpl/template.py | 14 +++++++++++++ tests/cellbg_selfclosing.py | 42 +++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 tests/cellbg_selfclosing.py diff --git a/docxtpl/template.py b/docxtpl/template.py index f20280a..3757a03 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -120,6 +120,13 @@ def colspan(m): flags=re.DOTALL, ) cell_xml = re.sub(r"", "", cell_xml, count=1) + # a self-closing would leave the inserted gridSpan outside of it + cell_xml = re.sub( + r"]*)?/>", + lambda mm: "" % (mm.group(1) or ""), + cell_xml, + count=1, + ) return re.sub( r"(]*>)", r'\1' % m.group(2), @@ -143,6 +150,13 @@ def cellbg(m): flags=re.DOTALL, ) cell_xml = re.sub(r"", "", cell_xml, count=1) + # a self-closing would leave the inserted shd outside of it + cell_xml = re.sub( + r"]*)?/>", + lambda mm: "" % (mm.group(1) or ""), + cell_xml, + count=1, + ) return re.sub( r"(]*>)", r'\1' % m.group(2), diff --git a/tests/cellbg_selfclosing.py b/tests/cellbg_selfclosing.py new file mode 100644 index 0000000..35387ce --- /dev/null +++ b/tests/cellbg_selfclosing.py @@ -0,0 +1,42 @@ +# Regression test for #559: pandoc-produced tables collapse empty cell +# properties to a self-closing , which used to make cellbg and +# colspan insert / as a sibling after it instead of +# inside, so Word silently ignored them. No template file needed, the +# checks work on patch_xml output directly. + +import re + +from docxtpl import DocxTemplate + +tpl = DocxTemplate("dummy.docx") + + +def patched(body): + return tpl.patch_xml("%s" % body) + + +def assert_inside_tcpr(xml, element): + m = re.search(r"]*>(.*?)", xml, flags=re.DOTALL) + assert m, "no expanded pair in: %s" % xml + assert element in m.group(1), "%s not inside : %s" % (element, xml) + + +# self-closing (the #559 case) +xml = patched("{% cellbg color %}x") +assert_inside_tcpr(xml, "{% colspan span %}x") +assert_inside_tcpr(xml, "{% cellbg color %}x') +assert_inside_tcpr(xml, " keeps working as before +xml = patched( + '{% cellbg color %}x' +) +assert_inside_tcpr(xml, "