Added method escape_values. Exclusively for Python3.

This commit is contained in:
Max P 2018-11-05 18:17:43 -08:00
parent 5ee43cf3e1
commit 40bf39cde7
2 changed files with 50 additions and 3 deletions

View File

@ -19,13 +19,12 @@ try:
except ImportError: except ImportError:
# cgi.escape is deprecated in python 3.7 # cgi.escape is deprecated in python 3.7
from cgi import escape from cgi import escape
import HTMLParser
unescape = HTMLParser.HTMLParser().unescape
import re import re
import six import six
import binascii import binascii
import os import os
import zipfile import zipfile
import sys
NEWLINE_XML = '</w:t><w:br/><w:t xml:space="preserve">' NEWLINE_XML = '</w:t><w:br/><w:t xml:space="preserve">'
NEWPARAGRAPH_XML = '</w:t></w:r></w:p><w:p><w:r><w:t xml:space="preserve">' NEWPARAGRAPH_XML = '</w:t></w:r></w:p><w:p><w:r><w:t xml:space="preserve">'
@ -171,7 +170,43 @@ class DocxTemplate(object):
def map_headers_footers_xml(self, relKey, xml): def map_headers_footers_xml(self, relKey, xml):
self.docx._part._rels[relKey]._target._blob = xml self.docx._part._rels[relKey]._target._blob = xml
def render(self,context,jinja_env=None): @staticmethod
def escape_values(context):
"""Escape strings for an XML Word document
which may contain <, >, &, ', and ".
"""
def escape_recursively(d):
"""Escape string values of the passed :dict: `d` in-place
including nested dictionaries.
"""
nonlocal hash_values
for k, v in d.items():
if isinstance(v, dict):
hash_value = id(v)
if hash_value not in hash_values:
hash_values.add(hash_value)
escape_recursively(v)
else:
# Avoid dict, Listing, InlineImage, RichText, etc. classes
# by comparing v to str. Do not use try-except.
if isinstance(v, str):
# Unescape at first to avoid secondary escaping
d[k] = escape(unescape(v))
# Avoid RecursionError (if back edges, i.e. cycles, exist)
# by using a set of hash values of iterated dictionaries.
hash_values = {id(context), }
escape_recursively(context)
def render(self, context, jinja_env=None):
if sys.version_info >= (3, 0):
self.escape_values(context)
else:
# Sorry folk, use awesome Python3 such as 3.6
pass
# Body # Body
xml_src = self.build_xml(context,jinja_env) xml_src = self.build_xml(context,jinja_env)

12
tests/escape_auto.py Normal file
View File

@ -0,0 +1,12 @@
from docxtpl import *
tpl = DocxTemplate("test_files/escape_tpl.docx")
context = {'myvar': R('"less than" must be escaped : <, this can be done with RichText() or R()'),
'myescvar':'It can be escaped with a "|e" jinja filter in the template too : < ',
'nlnp' : R('Here is a multiple\nlines\nstring\aand some\aother\aparagraphs\aNOTE: the current character styling is removed'),
'mylisting': Listing('the listing\nwith\nsome\nlines\nand special chars : <>&'),
}
tpl.render(context)
tpl.save("test_files/escape.docx")