\n, \a, \t and \f are now accepted in simple context string
This commit is contained in:
parent
b616daf50a
commit
44a0819625
22
CHANGES.rst
22
CHANGES.rst
@ -1,17 +1,10 @@
|
||||
0.11.0 (2020-10-19)
|
||||
-------------------
|
||||
- \\n, \\a, \\t and \\f are now accepted in simple context string. Thanks to chabErch@github
|
||||
|
||||
0.10.5 (2020-10-15)
|
||||
-------------------
|
||||
- Revert 0.10.4 as the XML code get corrupted
|
||||
|
||||
0.10.4 (2020-10-15)
|
||||
-------------------
|
||||
- \\n \\t and \\f are now accepted in simple context string (#307, #312)
|
||||
|
||||
0.10.1 (2020-08-23)
|
||||
-------------------
|
||||
- Remove extension testing (#297)
|
||||
|
||||
0.10.0 (2020-05-25)
|
||||
-------------------
|
||||
- Fix spaces missing in some cases (#116, #227)
|
||||
|
||||
0.9.2 (2020-04-26)
|
||||
@ -19,16 +12,9 @@
|
||||
- Fix #271
|
||||
- Code styling
|
||||
|
||||
0.9.0 (2020-04-15)
|
||||
-------------------
|
||||
- New syntax : {%- and -%} to merge lines/paragraphs
|
||||
|
||||
0.8.1 (2020-04-14)
|
||||
-------------------
|
||||
- fix #266
|
||||
|
||||
0.8.0 (2020-04-10)
|
||||
-------------------
|
||||
- docxtpl is now able to use latest python-docx (0.8.10). Thanks to Dutchy-@github.
|
||||
|
||||
0.7.0 (2020-04-09)
|
||||
|
||||
@ -142,6 +142,8 @@ As part of jinja2, one can used double braces::
|
||||
|
||||
{{ <var> }}
|
||||
|
||||
if ``<var>`` is a string, ``\n``, ``\a``, ``\t`` and ``\f`` will be translated respectively into newlines, new paragraphs, tabs and page breaks
|
||||
|
||||
But if ``<var>`` is a RichText_ object, you must specify that you are changing the actual 'run'::
|
||||
|
||||
{{r <var> }}
|
||||
@ -240,7 +242,7 @@ especially ``<``, ``>`` and ``&``. In order to use them, you must escape them. T
|
||||
* ``context = { 'var':escape('my text')}`` and ``{{ <var> }}`` in the template.
|
||||
* enable autoescaping when calling render method: ``tpl.render(context, autoescape=True)`` (default is autoescape=False)
|
||||
|
||||
The ``RichText()`` or ``R()`` offers newline, new paragraph, and page break features : just use ``\n``, ``\a``, or ``\f`` in the
|
||||
The ``RichText()`` or ``R()`` offers newline, new paragraph, and page break features : just use ``\n``, ``\a``, ``\t`` or ``\f`` in the
|
||||
text, they will be converted accordingly.
|
||||
|
||||
See tests/escape.py example for more informations.
|
||||
|
||||
@ -4,11 +4,10 @@ Created : 2015-03-12
|
||||
|
||||
@author: Eric Lapouyade
|
||||
'''
|
||||
__version__ = '0.11.0'
|
||||
|
||||
import functools
|
||||
import io
|
||||
|
||||
__version__ = '0.10.5'
|
||||
|
||||
from lxml import etree
|
||||
from docx import Document
|
||||
from docx.opc.oxml import parse_xml
|
||||
@ -28,11 +27,6 @@ import binascii
|
||||
import os
|
||||
import zipfile
|
||||
|
||||
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">'
|
||||
TAB_XML = '</w:t></w:r><w:r><w:tab/></w:r><w:r><w:t xml:space="preserve">'
|
||||
PAGE_BREAK = '</w:t><w:br w:type="page"/><w:t xml:space="preserve">'
|
||||
|
||||
|
||||
class DocxTemplate(object):
|
||||
""" Class for managing docx files as they were jinja2 templates """
|
||||
@ -234,8 +228,42 @@ class DocxTemplate(object):
|
||||
.replace('}_}', '}}')
|
||||
.replace('{_%', '{%')
|
||||
.replace('%_}', '%}'))
|
||||
dst_xml = self.resolve_listing(dst_xml)
|
||||
return dst_xml
|
||||
|
||||
def resolve_listing(self, xml):
|
||||
|
||||
def resolve_text(run_properties, paragraph_properties, m):
|
||||
xml = m[0].replace('\t', '</w:t></w:r>'
|
||||
'<w:r>%s<w:tab/></w:r>'
|
||||
'<w:r>%s<w:t xml:space="preserve">' % (run_properties, run_properties))
|
||||
xml = xml.replace('\a', '</w:t></w:r></w:p>'
|
||||
'<w:p>%s<w:r>%s<w:t xml:space="preserve">' % (paragraph_properties, run_properties))
|
||||
xml = xml.replace('\n', '</w:t><w:br/><w:t xml:space="preserve">')
|
||||
xml = xml.replace('\f', '</w:t></w:r></w:p>'
|
||||
'<w:p><w:r><w:br w:type="page"/></w:r></w:p>'
|
||||
'<w:p>%s<w:r>%s<w:t xml:space="preserve">' % (paragraph_properties, run_properties))
|
||||
return xml
|
||||
|
||||
def resolve_run(paragraph_properties, m):
|
||||
run_properties = re.search(r'<w:rPr>.*</w:rPr>', m[0])
|
||||
run_properties = run_properties[0] if run_properties else ''
|
||||
|
||||
p_resolve_text = lambda x:resolve_text(run_properties, paragraph_properties, x)
|
||||
return re.sub(r'<w:t(?:[^>]*)?>.*?</w:t>', p_resolve_text, m[0], flags=re.DOTALL)
|
||||
|
||||
def resolve_paragraph(m):
|
||||
paragraph_properties = re.search(r'<w:pPr>.*</w:pPr>', m[0])
|
||||
paragraph_properties = paragraph_properties[0] if paragraph_properties else ''
|
||||
|
||||
p_resolve_run = lambda x:resolve_run(paragraph_properties, x)
|
||||
|
||||
return re.sub(r'<w:r(?:[^>]*)?>.*?</w:r>', p_resolve_run, m[0], flags=re.DOTALL)
|
||||
|
||||
xml = re.sub(r'<w:p(?:[^>]*)?>.*?</w:p>', resolve_paragraph, xml, flags=re.DOTALL)
|
||||
|
||||
return xml
|
||||
|
||||
def build_xml(self, context, jinja_env=None):
|
||||
xml = self.get_xml()
|
||||
xml = self.patch_xml(xml)
|
||||
@ -684,11 +712,7 @@ class RichText(object):
|
||||
text = six.text_type(text)
|
||||
if not isinstance(text, six.text_type):
|
||||
text = text.decode('utf-8', errors='ignore')
|
||||
text = (escape(text)
|
||||
.replace('\n', NEWLINE_XML)
|
||||
.replace('\a', NEWPARAGRAPH_XML)
|
||||
.replace('\t', TAB_XML)
|
||||
.replace('\f', PAGE_BREAK))
|
||||
text = escape(text)
|
||||
|
||||
prop = u''
|
||||
|
||||
@ -756,11 +780,7 @@ class Listing(object):
|
||||
# If not a string : cast to string (ex: int, dict etc...)
|
||||
if not isinstance(text, (six.text_type, six.binary_type)):
|
||||
text = six.text_type(text)
|
||||
self.xml = (escape(text)
|
||||
.replace('\n', NEWLINE_XML)
|
||||
.replace('\a', NEWPARAGRAPH_XML)
|
||||
.replace('\t', TAB_XML)
|
||||
.replace('\f', PAGE_BREAK))
|
||||
self.xml = escape(text)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.xml
|
||||
|
||||
@ -7,13 +7,20 @@ context = {
|
||||
'"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'
|
||||
),
|
||||
'nlnp': R('Here is a multiple\nlines\nstring\aand some\aother\aparagraphs',
|
||||
color='#ff00ff'),
|
||||
'mylisting': Listing(
|
||||
'the listing\nwith\nsome\nlines\nand special chars : <>&\f ... and a page break'
|
||||
'the listing\nwith\nsome\nlines\nand special chars : <>& ...'
|
||||
),
|
||||
'page_break': R('\f'),
|
||||
'new_listing':"""
|
||||
This is a new listing
|
||||
Now, does not require Listing() Object
|
||||
Here is a \t tab\a
|
||||
Here is a new paragraph\a
|
||||
Here is a page break : \f
|
||||
That's it
|
||||
""",
|
||||
}
|
||||
|
||||
tpl.render(context)
|
||||
|
||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user