From e9b9a8bf3ff26050d394781047e9e591b9361935 Mon Sep 17 00:00:00 2001 From: elapouya Date: Fri, 13 Mar 2015 11:59:50 +0100 Subject: [PATCH] First running version --- .project | 17 +++++++ .pydevproject | 5 ++ .settings/org.eclipse.core.resources.prefs | 2 + docxtpl/__init__.py | 56 ++++++++++++++++++++- tests/__init__.py | 0 tests/order.py | 19 +++++++ tests/test_files/order.docx | Bin 0 -> 9465 bytes tests/test_files/order_tpl.docx | Bin 0 -> 13048 bytes 8 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 .project create mode 100644 .pydevproject create mode 100644 .settings/org.eclipse.core.resources.prefs create mode 100644 tests/__init__.py create mode 100644 tests/order.py create mode 100644 tests/test_files/order.docx create mode 100644 tests/test_files/order_tpl.docx diff --git a/.project b/.project new file mode 100644 index 0000000..ddf0128 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + python-docx-template + + + + + + org.python.pydev.PyDevBuilder + + + + + + org.python.pydev.pythonNature + + diff --git a/.pydevproject b/.pydevproject new file mode 100644 index 0000000..40e9f40 --- /dev/null +++ b/.pydevproject @@ -0,0 +1,5 @@ + + +Default +python 2.7 + diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..add17fd --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding//docxtpl/__init__.py=utf-8 diff --git a/docxtpl/__init__.py b/docxtpl/__init__.py index c1ce39c..c882275 100644 --- a/docxtpl/__init__.py +++ b/docxtpl/__init__.py @@ -7,10 +7,64 @@ Created : 2015-03-12 __version__ = '0.1.1' +from lxml import etree +from docx import Document +from jinja2 import Template +import copy +import re class DocxTemplate(object): """ Class for managing docx files as they were jinja2 templates """ - pass + def __init__(self, docx): + self.docx = Document(docx) + + def __getattr__(self, name): + return getattr(self.docx, name) + + def build_xml(self,context): + src_xml = etree.tostring(self.docx._element.body, pretty_print=True) + + with open('/tmp/docx1.xml','w') as fh: + fh.write(src_xml) + + # strip all xml tags inside {% %} and {{ }} + # that Microsoft word can insert into xml code for this part of the document + def striptags(m): + return re.sub('.*?(|]*>)','',m.group(0),flags=re.DOTALL) + src_xml = re.sub(r'{%(?:(?!%}).)*|{{(?:(?!}}).)*',striptags,src_xml,flags=re.DOTALL) + + # manage table cell background color + def cellbg(m): + cell_xml = m.group(1) + m.group(3) + cell_xml = re.sub(r'](?:(?!]).)*.*?','',cell_xml,flags=re.DOTALL) + return re.sub(r'()',r'\1{{ %s}}\2' % m.group(2), cell_xml) + src_xml = re.sub(r'(](?:(?!]).)*){%\s*cellbg\s+([^%]*)\s*%}(.*?)',cellbg,src_xml,flags=re.DOTALL) + + # replace xml code corresponding to the paragraph containing {{{ xxx }}} by {{ xxx }} + src_xml = re.sub(r'](?:(?!]).)*{{{([^}]*)}}}.*?',r'{{\1}}',src_xml,flags=re.DOTALL) + + # replace xml code corresponding to the row containing {% tr-xxx template tag by {% xxx template tag itself + src_xml = re.sub(r'](?:(?!]).)*{%\s*tr-([^%]*%}).*?',r'{% \1',src_xml,flags=re.DOTALL) + + # replace xml code corresponding to the paragraph containing {% p-xxx template tag by {% xxx template tag itself + src_xml = re.sub(r'](?:(?!]).)*{%\s*p-([^%]*%}).*?',r'{% \1',src_xml,flags=re.DOTALL) + + with open('/tmp/docx2.xml','w') as fh: + fh.write(src_xml) + + template = Template(src_xml) + dst_xml = template.render(context) + + return dst_xml + + def map_xml(self,xml): + root = self.docx._element + body = root.body + root.replace(body,etree.fromstring(xml)) + + def render(self,context): + xml = self.build_xml(context) + self.map_xml(xml) class Subdoc(object): """ Class for subdocumentation insertion into master document """ diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/order.py b/tests/order.py new file mode 100644 index 0000000..a7d90ee --- /dev/null +++ b/tests/order.py @@ -0,0 +1,19 @@ +from docxtpl import DocxTemplate + +tpl=DocxTemplate('test_files/order_tpl.docx') + +context = { + 'customer_name' : 'Eric', + 'items' : [ + {'desc' : 'Python interpreters', 'qty' : 2, 'price' : 'FREE' }, + {'desc' : 'Django projects', 'qty' : 5403, 'price' : 'FREE' }, + {'desc' : 'Guido', 'qty' : 1, 'price' : '100,000,000.00' }, + ], + 'in_europe' : True, + 'is_paid': False, + 'company_name' : 'The World Wide company', + 'total_price' : '100,000,000.00' +} + +tpl.render(context) +tpl.save('test_files/order.docx') diff --git a/tests/test_files/order.docx b/tests/test_files/order.docx new file mode 100644 index 0000000000000000000000000000000000000000..a4874bc5cc445613fd44191f5f4a4dbb26137a4e GIT binary patch literal 9465 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

BihElu(nENBlO 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 literal 0 HcmV?d00001