Port txt report to new report engine.

bzr revid: p_christ@hol.gr-20090507171706-ozmwxiuwv5jf1q4p
This commit is contained in:
P. Christeas 2009-05-07 20:17:06 +03:00
parent 2ccc626184
commit eac36b4a19
8 changed files with 183 additions and 80 deletions

View File

@ -205,8 +205,8 @@ class report_rml(report_int):
obj.render()
return obj.get()
def create_txt(self, xml, logo=None, title=None):
obj = render.rml2txt(xml, self.bin_datas)
def create_txt(self, rml,localcontext, logo=None, title=None):
obj = render.rml2txt(rml, localcontext, self.bin_datas)
obj.render()
return obj.get().encode('utf-8')

View File

@ -6,7 +6,7 @@ html_parents = ['tr','body','div']
sxw_parents = ['{http://openoffice.org/2000/table}table-row','{http://openoffice.org/2000/office}body','{http://openoffice.org/2000/text}section']
class report(object):
def preprocess_rml(self, root_node,type='pdf'):
def preprocess_rml(self, root_node,ntype='pdf'):
_regex1 = re.compile("\[\[(.*?)(repeatIn\(.*?\s*,\s*[\'\"].*?[\'\"]\s*(?:,\s*(.*?)\s*)?\s*\))(.*?)\]\]")
_regex11= re.compile("\[\[(.*?)(repeatIn\(.*?\s*\(.*?\s*[\'\"].*?[\'\"]\s*\),[\'\"].*?[\'\"](?:,\s*(.*?)\s*)?\s*\))(.*?)\]\]")
_regex2 = re.compile("\[\[(.*?)(removeParentNode\(\s*(?:['\"](.*?)['\"])\s*\))(.*?)\]\]")
@ -35,9 +35,9 @@ class report(object):
if len(txt.group(4)) > 1:
return " "
match = rml_parents
if type in ['odt','sxw']:
if ntype in ['odt','sxw']:
match = sxw_parents
if type =='html2html':
if ntype =='html2html':
match = html_parents
if txt.group(3):
match = [txt.group(3)]
@ -51,7 +51,7 @@ class report(object):
t = _regex11.sub(_sub1, node.text)
t = _regex3.sub(_sub3, t)
node.text = _regex2.sub(_sub2, t)
self.preprocess_rml(node,type)
self.preprocess_rml(node,ntype)
return root_node
if __name__=='__main__':

View File

@ -52,13 +52,14 @@ class rml2html(render.render):
return htmlizer.parseString(self.rml,self.localcontext)
class rml2txt(render.render):
def __init__(self, xml, datas={}):
def __init__(self, rml, localcontext= None, datas={}):
super(rml2txt, self).__init__(datas)
self.xml = xml
self.rml = rml
self.localcontext = localcontext
self.output_type = 'txt'
def _render(self):
return txtizer.parseString(self.xml)
return txtizer.parseString(self.rml, self.localcontext)
class odt2odt(render.render):
def __init__(self, rml, localcontext = None, datas = {}):

View File

@ -455,7 +455,7 @@ if __name__=="__main__":
rml2html_help()
print parseString(file(sys.argv[1], 'r').read()),
else:
print 'Usage: trml2pdf input.rml >output.pdf'
print 'Try \'trml2pdf --help\' for more information.'
print 'Usage: rml2html input.rml >output.html'
print 'Try \'rml2html --help\' for more information.'
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -20,7 +20,7 @@
#
##############################################################################
from rml2txt import parseString
from rml2txt import parseString, parseNode
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -40,8 +40,9 @@
import sys
import StringIO
import xml.dom.minidom
import copy
from lxml import etree
import base64
import utils
@ -80,6 +81,8 @@ class textbox():
"""Append some text to the current line.
Mimic the HTML behaviour, where all whitespace evaluates to
a single space """
if not txt:
return
bs = es = False
if txt[0].isspace():
bs = True
@ -135,7 +138,7 @@ class textbox():
class _flowable(object):
def __init__(self, template, doc):
def __init__(self, template, doc,localcontext):
self._tags = {
'1title': self._tag_title,
'1spacer': self._tag_spacer,
@ -149,6 +152,7 @@ class _flowable(object):
}
self.template = template
self.doc = doc
self.localcontext = localcontext
self.nitags = []
self.tbox = None
@ -174,7 +178,7 @@ class _flowable(object):
return node.toxml()
def _tag_spacer(self, node):
length = 1+int(utils.unit_get(node.getAttribute('length')))/35
length = 1+int(utils.unit_get(node.get('length')))/35
return "\n"*length
def _tag_table(self, node):
@ -182,14 +186,14 @@ class _flowable(object):
saved_tb = self.tb
self.tb = None
sizes = None
if node.hasAttribute('colWidths'):
sizes = map(lambda x: utils.unit_get(x), node.getAttribute('colWidths').split(','))
if node.get('colWidths'):
sizes = map(lambda x: utils.unit_get(x), node.get('colWidths').split(','))
trs = []
for n in node.childNodes:
if n.nodeType == node.ELEMENT_NODE and n.localName == 'tr':
for n in utils._child_get(node,self):
if n.tag == 'tr':
tds = []
for m in n.childNodes:
if m.nodeType == node.ELEMENT_NODE and m.localName == 'td':
for m in utils._child_get(n,self):
if m.tag == 'td':
self.tb = textbox()
self.rec_render_cnodes(m)
tds.append(self.tb)
@ -228,21 +232,19 @@ class _flowable(object):
self.rec_render_cnodes(node)
def rec_render_cnodes(self,node):
for n in node.childNodes:
self.rec_render(n)
self.tb.appendtxt(utils._process_text(self, node.text or ''))
for n in utils._child_get(node,self):
self.rec_render(n)
self.tb.appendtxt(utils._process_text(self, node.tail or ''))
def rec_render(self,node):
""" Recursive render: fill outarr with text of current node
"""
if node.nodeType == node.TEXT_NODE:
self.tb.appendtxt(node.data)
elif node.nodeType==node.ELEMENT_NODE:
if node.localName in self._tags:
self._tags[node.localName](node)
if node.tag != None:
if node.tag in self._tags:
self._tags[node.tag](node)
else:
self.warn_nitag(node.localName)
else:
verbose("Unknown nodeType: %d" % node.nodeType)
self.warn_nitag(node.tag)
def render(self, node):
self.tb= textbox()
@ -288,8 +290,8 @@ class _rml_tmpl_frame(_rml_tmpl_tag):
class _rml_tmpl_draw_string(_rml_tmpl_tag):
def __init__(self, node, style):
self.posx = utils.unit_get(node.getAttribute('x'))
self.posy = utils.unit_get(node.getAttribute('y'))
self.posx = utils.unit_get(node.get('x'))
self.posy = utils.unit_get(node.get('y'))
aligns = {
'drawString': 'left',
'drawRightString': 'right',
@ -348,12 +350,12 @@ class _rml_stylesheet(object):
'alignment': lambda x: ('text-align',str(x))
}
result = ''
for ps in stylesheet.getElementsByTagName('paraStyle'):
for ps in stylesheet.findall('paraStyle'):
attr = {}
attrs = ps.attributes
for i in range(attrs.length):
name = attrs.item(i).localName
attr[name] = ps.getAttribute(name)
attr[name] = ps.get(name)
attrs = []
for a in attr:
if a in self._tags:
@ -369,9 +371,9 @@ class _rml_draw_style(object):
def __init__(self):
self.style = {}
self._styles = {
'fill': lambda x: {'td': {'color':x.getAttribute('color')}},
'setFont': lambda x: {'td': {'font-size':x.getAttribute('size')+'px'}},
'stroke': lambda x: {'hr': {'color':x.getAttribute('color')}},
'fill': lambda x: {'td': {'color':x.get('color')}},
'setFont': lambda x: {'td': {'font-size':x.get('size')+'px'}},
'stroke': lambda x: {'hr': {'color':x.get('color')}},
}
def update(self, node):
if node.localName in self._styles:
@ -391,7 +393,8 @@ class _rml_draw_style(object):
return ';'.join(['%s:%s' % (x[0],x[1]) for x in self.style[tag].items()])
class _rml_template(object):
def __init__(self, template):
def __init__(self, localcontext, out, node, doc, images={}, path='.', title=None):
self.localcontext = localcontext
self.frame_pos = -1
self.frames = []
self.template_order = []
@ -404,16 +407,16 @@ class _rml_template(object):
'lines': _rml_tmpl_draw_lines
}
self.style = _rml_draw_style()
for pt in template.getElementsByTagName('pageTemplate'):
for pt in node.findall('pageTemplate'):
frames = {}
id = pt.getAttribute('id')
id = pt.get('id')
self.template_order.append(id)
for tmpl in pt.getElementsByTagName('frame'):
posy = int(utils.unit_get(tmpl.getAttribute('y1'))) #+utils.unit_get(tmpl.getAttribute('height')))
posx = int(utils.unit_get(tmpl.getAttribute('x1')))
frames[(posy,posx,tmpl.getAttribute('id'))] = _rml_tmpl_frame(posx, utils.unit_get(tmpl.getAttribute('width')))
for tmpl in template.getElementsByTagName('pageGraphics'):
for n in tmpl.childNodes:
for tmpl in pt.findall('frame'):
posy = int(utils.unit_get(tmpl.get('y1'))) #+utils.unit_get(tmpl.get('height')))
posx = int(utils.unit_get(tmpl.get('x1')))
frames[(posy,posx,tmpl.get('id'))] = _rml_tmpl_frame(posx, utils.unit_get(tmpl.get('width')))
for tmpl in node.findall('pageGraphics'):
for n in tmpl.getchildren():
if n.nodeType==n.ELEMENT_NODE:
if n.localName in self._tags:
t = self._tags[n.localName](n, self.style)
@ -480,21 +483,46 @@ class _rml_template(object):
return result
class _rml_doc(object):
def __init__(self, data):
self.dom = xml.dom.minidom.parseString(data)
self.filename = self.dom.documentElement.getAttribute('filename')
def __init__(self, node, localcontext, images={}, path='.', title=None):
self.localcontext = localcontext
self.etree = node
self.filename = self.etree.get('filename')
self.result = ''
def render(self, out):
template = _rml_template(self.dom.documentElement.getElementsByTagName('template')[0])
f = _flowable(template, self.dom)
self.result += f.render(self.dom.documentElement.getElementsByTagName('story')[0])
del f
#el = self.etree.findall('docinit')
#if el:
#self.docinit(el)
#el = self.etree.findall('stylesheet')
#self.styles = _rml_styles(el,self.localcontext)
el = self.etree.findall('template')
self.result =""
if len(el):
pt_obj = _rml_template(self.localcontext, out, el[0], self)
stories = utils._child_get(self.etree, self, 'story')
for story in stories:
if self.result:
self.result += '\f'
f = _flowable(pt_obj,story,self.localcontext)
self.result += f.render(story)
del f
else:
self.result = "<cannot render w/o template>"
self.result += '\n'
out.write( self.result)
def parseString(data, fout=None):
r = _rml_doc(data)
def parseNode(rml, localcontext = {},fout=None, images={}, path='.',title=None):
node = etree.XML(rml)
r = _rml_doc(node, localcontext, images, path, title=title)
fp = StringIO.StringIO()
r.render(fp)
return fp.getvalue()
def parseString(rml, localcontext = {},fout=None, images={}, path='.',title=None):
node = etree.XML(rml)
r = _rml_doc(node, localcontext, images, path, title=title)
if fout:
fp = file(fout,'wb')
r.render(fp)

View File

@ -1,8 +1,8 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
# This program is free software: you can redistribute it and/or modify
@ -20,37 +20,110 @@
#
##############################################################################
# trml2pdf - An RML to PDF converter
# Copyright (C) 2003, Fabien Pinckaers, UCL, FSA
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import re
import reportlab
import reportlab.lib.units
from lxml import etree
_regex = re.compile('\[\[(.+?)\]\]')
def _child_get(node, self=None, tagname=None):
for n in node:
if self and self.localcontext and n.get('rml_loop', False):
oldctx = self.localcontext
for ctx in eval(n.get('rml_loop'),{}, self.localcontext):
self.localcontext.update(ctx)
if (tagname is None) or (n.tag==tagname):
if n.get('rml_except', False):
try:
eval(n.get('rml_except'), {}, self.localcontext)
except:
continue
if n.get('rml_tag'):
try:
(tag,attr) = eval(n.get('rml_tag'),{}, self.localcontext)
n2 = copy.copy(n)
n2.tag = tag
n2.attrib.update(attr)
yield n2
except:
yield n
else:
yield n
self.localcontext = oldctx
continue
if self and self.localcontext and n.get('rml_except', False):
try:
eval(n.get('rml_except'), {}, self.localcontext)
except:
continue
if (tagname is None) or (n.tag==tagname):
yield n
def _process_text(self, txt):
if not self.localcontext:
return txt
if not txt:
return ''
result = ''
sps = _regex.split(txt)
while sps:
# This is a simple text to translate
result += self.localcontext.get('translate', lambda x:x)(sps.pop(0))
if sps:
try:
txt2 = eval(sps.pop(0),self.localcontext)
except:
txt2 = ''
if type(txt2) == type(0) or type(txt2) == type(0.0):
txt2 = str(txt2)
if type(txt2)==type('') or type(txt2)==type(u''):
result += txt2
return result
def text_get(node):
rc = ''
for node in node.childNodes:
if node.nodeType == node.TEXT_NODE:
rc = rc + node.data
for node in node.getchildren():
rc = rc + node.text
return rc
units = [
(re.compile('^(-?[0-9\.]+)\s*in$'), reportlab.lib.units.inch),
(re.compile('^(-?[0-9\.]+)\s*cm$'), reportlab.lib.units.cm),
(re.compile('^(-?[0-9\.]+)\s*cm$'), reportlab.lib.units.cm),
(re.compile('^(-?[0-9\.]+)\s*mm$'), reportlab.lib.units.mm),
(re.compile('^(-?[0-9\.]+)\s*px$'), 0.7),
(re.compile('^(-?[0-9\.]+)\s*$'), 1)
]
def unit_get(size):
global units
for unit in units:
res = unit[0].search(size, 0)
if res:
return int(unit[1]*float(res.group(1))*1.3)
if size:
for unit in units:
res = unit[0].search(size, 0)
if res:
return unit[1]*float(res.group(1))
return False
def tuple_int_get(node, attr_name, default=None):
if not node.hasAttribute(attr_name):
if not node.get(attr_name):
return default
res = [int(x) for x in node.getAttribute(attr_name).split(',')]
res = [int(x) for x in node.get(attr_name).split(',')]
return res
def bool_get(value):
@ -59,17 +132,18 @@ def bool_get(value):
def attr_get(node, attrs, dict={}):
res = {}
for name in attrs:
if node.hasAttribute(name):
res[name] = unit_get(node.getAttribute(name))
if node.get(name):
res[name] = unit_get(node.get(name))
for key in dict:
if node.hasAttribute(key):
if node.get(key):
if dict[key]=='str':
res[key] = str(node.getAttribute(key))
res[key] = str(node.get(key))
elif dict[key]=='bool':
res[key] = bool_get(node.getAttribute(key))
res[key] = bool_get(node.get(key))
elif dict[key]=='int':
res[key] = int(node.getAttribute(key))
res[key] = int(node.get(key))
elif dict[key]=='unit':
res[key] = unit_get(node.get(key))
return res
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -309,7 +309,7 @@ class rml_parse(object):
head_dom = etree.XML(rml_head)
for tag in head_dom.getchildren():
found = rml_dom.find('.//'+tag.tag)
if found:
if found is not None:
if tag.get('position'):
found.append(tag)
else :
@ -359,12 +359,12 @@ class report_sxw(report_rml, preprocess.report):
report_type = report_xml.report_type
if report_type in ['sxw','odt']:
fnct = self.create_source_odt
elif report_type in ['pdf','raw','html']:
elif report_type in ['pdf','raw','txt','html']:
fnct = self.create_source_pdf
elif report_type=='html2html':
fnct = self.create_source_html2html
else:
raise 'Unknown Report Type'
raise Exception('Unknown Report Type: '+report_type)
return fnct(cr, uid, ids, data, report_xml, context)
def create_source_odt(self, cr, uid, ids, data, report_xml, context=None):