diff --git a/docxtpl/template.py b/docxtpl/template.py index f20280a..72f66ff 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -87,6 +87,15 @@ def patch_xml(self, src_xml): strip all unnecessary xml tags, manage table cell background color and colspan, unescape html entities, etc...""" + # Join escaped Jinja delimiters that Word has split across runs. Limit the + # removable XML to tags inside one paragraph so unrelated text is untouched. + split_run_gap = ( + r"(?:(?:(?!))<[^>]+>)*]*)?>)?" + ) + for escaped_delimiter in ("{_{", "}_}", "{_%", "%_}"): + pattern = split_run_gap.join(map(re.escape, escaped_delimiter)) + src_xml = re.sub(pattern, escaped_delimiter, src_xml) + # replace {{ by {{ ( works with {{ }} {% and %} {# and #}) src_xml = re.sub( r"(?<={)(<[^>]*>)+(?=[\{%\#])|(?<=[%\}\#])(<[^>]*>)+(?=\})", diff --git a/tests/escaping_delimiters.py b/tests/escaping_delimiters.py new file mode 100644 index 0000000..de6f182 --- /dev/null +++ b/tests/escaping_delimiters.py @@ -0,0 +1,43 @@ +from pathlib import Path + +from docx import Document +from docxtpl import DocxTemplate + + +output_dir = Path(__file__).parent / "output" +output_dir.mkdir(exist_ok=True) +template_path = output_dir / "escaping_delimiters_split_tpl.docx" +result_path = output_dir / "escaping_delimiters_split.docx" + +escaped_delimiters = ("{_%", "%_}", "{_{", "}_}") +expected_delimiters = ("{%", "%}", "{{", "}}") + +template = Document() + +for delimiter in escaped_delimiters: + template.add_paragraph(delimiter) + +template.add_paragraph() + +for delimiter in escaped_delimiters: + paragraph = template.add_paragraph() + for character in delimiter: + paragraph.add_run(character) + +# These are not escaped delimiters and must not be changed. +template.add_paragraph("{a_{hello") +template.add_paragraph("{f_{") +template.save(template_path) + +doc = DocxTemplate(template_path) +doc.render({}) +doc.save(result_path) + +paragraphs = [paragraph.text for paragraph in Document(result_path).paragraphs] +assert paragraphs == [ + *expected_delimiters, + "", + *expected_delimiters, + "{a_{hello", + "{f_{", +]