Refactoring. Native support to ODF files added. A new control tag '{% tablerow_tag %}'. This tag replace the row internal XML with the control-flow a control tag near it. Used for table genation.
This commit is contained in:
parent
4973bb36ab
commit
8d5104be4c
2 changed files with 100 additions and 43 deletions
|
|
@ -1,2 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2"><office:scripts/><office:font-face-decls><style:font-face style:name="Lohit Hindi1" svg:font-family="'Lohit Hindi'"/><style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'" style:font-family-generic="roman" style:font-pitch="variable"/><style:font-face style:name="Liberation Sans" svg:font-family="'Liberation Sans'" style:font-family-generic="swiss" style:font-pitch="variable"/><style:font-face style:name="Lohit Hindi" svg:font-family="'Lohit Hindi'" style:font-family-generic="system" style:font-pitch="variable"/><style:font-face style:name="WenQuanYi Micro Hei" svg:font-family="'WenQuanYi Micro Hei'" style:font-family-generic="system" style:font-pitch="variable"/></office:font-face-decls><office:automatic-styles/><office:body><office:text><text:sequence-decls><text:sequence-decl text:display-outline-level="0" text:name="Illustration"/><text:sequence-decl text:display-outline-level="0" text:name="Table"/><text:sequence-decl text:display-outline-level="0" text:name="Text"/><text:sequence-decl text:display-outline-level="0" text:name="Drawing"/></text:sequence-decls><text:p text:style-name="Standard">Hello {{ record.name }}</text:p><text:p text:style-name="Standard"/><text:p text:style-name="Standard">You are from {{ record.country }}</text:p><text:p text:style-name="Standard"/><text:p text:style-name="Standard">{% if record.age %}{{ record.age }}{% else %}Unknow age{% endif %}</text:p></office:text></office:body></office:document-content>
|
|
||||||
139
renders.py
139
renders.py
|
|
@ -43,6 +43,10 @@ except ImportError:
|
||||||
|
|
||||||
|
|
||||||
PARAGRAPH_TAG = '{% paragraph_tag %}'
|
PARAGRAPH_TAG = '{% paragraph_tag %}'
|
||||||
|
TABLEROW_TAG = '{% tablerow_tag %}'
|
||||||
|
|
||||||
|
OOO_PARAGRAPH_NODE = 'text:p'
|
||||||
|
OOO_TABLEROW_NODE = 'table:table-row'
|
||||||
|
|
||||||
class BaseRender():
|
class BaseRender():
|
||||||
"""
|
"""
|
||||||
|
|
@ -55,24 +59,24 @@ class BaseRender():
|
||||||
|
|
||||||
def __init__(self, xml_doc, **template_args):
|
def __init__(self, xml_doc, **template_args):
|
||||||
self.template_vars = template_args
|
self.template_vars = template_args
|
||||||
self.xml_document = xml.dom.minidom.parse(xml_doc)
|
self.xml_document = xml.dom.minidom.parseString(xml_doc)
|
||||||
body = self.xml_document.getElementsByTagName('office:body')
|
body = self.xml_document.getElementsByTagName('office:body')
|
||||||
self.content_body = body and body[0]
|
self.content_body = body and body[0]
|
||||||
|
|
||||||
# ------------------------------------------------------------------------@
|
# ------------------------------------------------------------------------@
|
||||||
|
|
||||||
|
|
||||||
def get_paragraph_parent(self, node):
|
def get_parent_of(self, node, parent_type):
|
||||||
"""
|
"""
|
||||||
Returns the first node's parent with name "text:p"
|
Returns the first node's parent with name of parent_type
|
||||||
If parent "text:p" is not found, returns None.
|
If parent "text:p" is not found, returns None.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if hasattr(node, 'parentNode'):
|
if hasattr(node, 'parentNode'):
|
||||||
if node.parentNode.nodeName.lower() == 'text:p':
|
if node.parentNode.nodeName.lower() == parent_type:
|
||||||
return node.parentNode
|
return node.parentNode
|
||||||
else:
|
else:
|
||||||
return get_paragraph_parent(node.parentNode)
|
return self.get_parent_of(node.parentNode, parent_type)
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
@ -84,57 +88,66 @@ class BaseRender():
|
||||||
Once the XML have been prepared, this routine is called
|
Once the XML have been prepared, this routine is called
|
||||||
to do the actual rendering.
|
to do the actual rendering.
|
||||||
"""
|
"""
|
||||||
|
# print self.xml_document.toprettyxml()
|
||||||
template = TemplateEngine(self.xml_document.toxml())
|
template = TemplateEngine(self.xml_document.toxml())
|
||||||
return template.render(**self.template_vars)
|
return template.render(**self.template_vars)
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
def scan_child_nodes(self, nodes):
|
def prepare_document(self):
|
||||||
|
"""
|
||||||
|
Search in every paragraph node in the document.
|
||||||
|
"""
|
||||||
|
paragraphs = self.content_body.getElementsByTagName('text:p')
|
||||||
|
|
||||||
|
for paragraph in paragraphs:
|
||||||
|
self.scan_paragraph_child_nodes(paragraph)
|
||||||
|
|
||||||
|
|
||||||
|
def scan_paragraph_child_nodes(self, nodes):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if nodes.hasChildNodes():
|
if nodes.hasChildNodes():
|
||||||
child_nodes = nodes.childNodes
|
child_nodes = nodes.childNodes
|
||||||
|
|
||||||
for node in child_nodes:
|
for node in child_nodes:
|
||||||
if node.nodeType == node.TEXT_NODE:
|
if node.nodeType == node.TEXT_NODE:
|
||||||
node_text = node.data.lower()
|
self.handle_special_tags(node)
|
||||||
|
|
||||||
# replace a paragraph node with contained tags
|
|
||||||
# if tag PARAGRAPH_TAG is in paragraph content.
|
|
||||||
|
|
||||||
if node_text.find(PARAGRAPH_TAG) > -1:
|
|
||||||
# Get this node text:p parent
|
|
||||||
paragraph_node = self.get_paragraph_parent(node)
|
|
||||||
paragraph_parent = paragraph_node.parentNode
|
|
||||||
|
|
||||||
|
|
||||||
# Discar PARAGRAPH_TAG
|
|
||||||
pgraph_node_text = \
|
|
||||||
paragraph_node.toxml().replace(PARAGRAPH_TAG, '')
|
|
||||||
|
|
||||||
# replace text:p node's XML with its contained templates tags.
|
|
||||||
new_node_text = \
|
|
||||||
' '.join(re.findall('(\{.*?\})', pgraph_node_text))
|
|
||||||
|
|
||||||
new_node = xml_document.createTextNode(new_node_text)
|
|
||||||
paragraph_parent.replaceChild(new_node, paragraph_node)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if node.hasChildNodes():
|
if node.hasChildNodes():
|
||||||
scan_child_nodes(node)
|
self.scan_paragraph_child_nodes(node)
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
def handle_special_tags(self):
|
def handle_special_tags(self, node):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
"""
|
"""
|
||||||
paragraphs = self.content_body.getElementsByTagName('text:p')
|
node_text = node.data.lower()
|
||||||
for paragraph in paragraphs:
|
replace_node = None
|
||||||
self.scan_child_nodes(paragraph)
|
|
||||||
|
if node_text.find(PARAGRAPH_TAG) > -1:
|
||||||
|
replace_node = self.get_parent_of(node, OOO_PARAGRAPH_NODE)
|
||||||
|
note_text = replace_node.toxml().replace(PARAGRAPH_TAG, '')
|
||||||
|
|
||||||
|
elif node_text.find(TABLEROW_TAG) > -1:
|
||||||
|
replace_node = self.get_parent_of(node, OOO_TABLEROW_NODE)
|
||||||
|
note_text = replace_node.toxml().replace(TABLEROW_TAG, '')
|
||||||
|
|
||||||
|
|
||||||
|
if replace_node is not None:
|
||||||
|
paragraph_parent = replace_node.parentNode
|
||||||
|
|
||||||
|
new_node_text = \
|
||||||
|
' '.join(re.findall('(\{.*?\})', note_text))
|
||||||
|
|
||||||
|
new_node = self.xml_document.createTextNode(new_node_text)
|
||||||
|
paragraph_parent.replaceChild(new_node, replace_node)
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
@ -145,22 +158,68 @@ class BaseRender():
|
||||||
to parse template engine tags
|
to parse template engine tags
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.handle_special_tags()
|
self.prepare_document()
|
||||||
|
|
||||||
return self.render_with_engine()
|
return self.render_with_engine()
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
data = {
|
from datetime import datetime
|
||||||
'name': u'Christopher Ramirez',
|
|
||||||
'country': 'Nicaragua'
|
document = {
|
||||||
|
'datetime': datetime.now()
|
||||||
}
|
}
|
||||||
|
|
||||||
render = BaseRender('content.xml', record=data)
|
countries = [
|
||||||
print render.render()
|
{'country': 'United States', 'capital': 'Washington'},
|
||||||
|
{'country': 'England', 'capital': 'London'},
|
||||||
|
{'country': 'Japan', 'capital': 'Tokio'},
|
||||||
|
{'country': 'Nicaragua', 'capital': 'Managua'},
|
||||||
|
{'country': 'Argentina', 'capital': 'Buenos aires'},
|
||||||
|
{'country': 'Chile', 'capital': 'Santiago'},
|
||||||
|
{'country': 'Mexico', 'capital': 'MExico City'},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# ODF is just a zipfile
|
||||||
|
input = zipfile.ZipFile( 'simple_template.odt', "r" )
|
||||||
|
|
||||||
|
# we cannot write directly to HttpResponse, so use StringIO
|
||||||
|
# text = StringIO.StringIO()
|
||||||
|
text = open('rendered.odt', 'wb')
|
||||||
|
# output document
|
||||||
|
output = zipfile.ZipFile( text, "w" )
|
||||||
|
|
||||||
|
# go through the files in source
|
||||||
|
for zi in input.filelist:
|
||||||
|
out = input.read( zi.filename )
|
||||||
|
|
||||||
|
if zi.filename == 'content.xml':
|
||||||
|
render = BaseRender(out, trademark={'owner':{}}, document=document, countries=countries)
|
||||||
|
out = render.render().encode('ascii', 'xmlcharrefreplace')
|
||||||
|
|
||||||
|
elif zi.filename == 'mimetype':
|
||||||
|
# mimetype is stored within the ODF
|
||||||
|
mimetype = out
|
||||||
|
|
||||||
|
output.writestr( zi.filename, out,
|
||||||
|
zipfile.ZIP_DEFLATED )
|
||||||
|
|
||||||
|
# close and finish
|
||||||
|
input.close()
|
||||||
|
output.close()
|
||||||
|
|
||||||
|
print "Template rendering finished! Check rendered.odt file."
|
||||||
|
|
||||||
|
# output_file.open('rendered.odt', 'w')
|
||||||
|
# output_file.write(output)
|
||||||
|
# output_file.close()
|
||||||
|
|
||||||
|
# render = BaseRender('content.xml', record=data)
|
||||||
|
# print render.render()
|
||||||
|
|
||||||
# xml_document = xml.dom.minidom.parse('content.xml')
|
# xml_document = xml.dom.minidom.parse('content.xml')
|
||||||
# doc_body = xml_document.getElementsByTagName('office:body')
|
# doc_body = xml_document.getElementsByTagName('office:body')
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue