2
# -*- coding: utf-8 -*-
4
# Copyright (C) 2005, Fabien Pinckaers, UCL, FSA
6
# This library is free software; you can redistribute it and/or
7
# modify it under the terms of the GNU Lesser General Public
8
# License as published by the Free Software Foundation; either
9
# version 2.1 of the License, or (at your option) any later version.
11
# This library is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
# Lesser General Public License for more details.
16
# You should have received a copy of the GNU Lesser General Public
17
# License along with this library; if not, write to the Free Software
18
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
import xml.dom.minidom
27
class _flowable(object):
28
def __init__(self, template, doc):
30
'title': self._tag_title,
31
'spacer': self._tag_spacer,
32
'para': self._tag_para,
33
'nextFrame': self._tag_next_frame,
34
'blockTable': self._tag_table,
35
'pageBreak': self._tag_page_break,
36
'setNextTemplate': self._tag_next_template,
38
self.template = template
41
def _tag_page_break(self, node):
44
def _tag_next_template(self, node):
47
def _tag_next_frame(self, node):
48
result=self.template.frame_stop()
50
result+=self.template.frame_start()
53
def _tag_title(self, node):
57
def _tag_spacer(self, node):
58
length = 1+int(utils.unit_get(node.getAttribute('length')))/35
61
def _tag_table(self, node):
63
if node.hasAttribute('colWidths'):
64
sizes = map(lambda x: utils.unit_get(x), node.getAttribute('colWidths').split(','))
65
tr = self.doc.createElement('tr')
67
td = self.doc.createElement('td')
68
td.setAttribute("width", str(s))
73
def _tag_para(self, node):
75
if node.hasAttribute('style'):
76
node.setAttribute('class', node.getAttribute('style'))
79
def render(self, node):
80
result = self.template.start()
81
result += self.template.frame_start()
82
for n in node.childNodes:
83
if n.nodeType==node.ELEMENT_NODE:
84
if n.localName in self._tags:
85
result += self._tags[n.localName](n)
88
#print 'tag', n.localName, 'not yet implemented!'
89
result += self.template.frame_stop()
90
result += self.template.end()
93
class _rml_tmpl_tag(object):
94
def __init__(self, *args):
102
def tag_mergeable(self):
105
class _rml_tmpl_frame(_rml_tmpl_tag):
106
def __init__(self, posx, width):
110
return '<table border="0" width="%d"><tr><td width="%d"> </td><td>' % (self.width+self.posx,self.posx)
114
return '</td></tr></table><br/>'
115
def tag_mergeable(self):
118
# An awfull workaround since I don't really understand the semantic behind merge.
119
def merge(self, frame):
122
class _rml_tmpl_draw_string(_rml_tmpl_tag):
123
def __init__(self, node, style):
124
self.posx = utils.unit_get(node.getAttribute('x'))
125
self.posy = utils.unit_get(node.getAttribute('y'))
127
'drawString': 'left',
128
'drawRightString': 'right',
129
'drawCentredString': 'center'
131
align = aligns[node.localName]
132
self.pos = [(self.posx, self.posy, align, utils.text_get(node), style.get('td'), style.font_size_get('td'))]
136
res = '<table border="0" cellpadding="0" cellspacing="0"><tr>'
139
for (x,y,align,txt, style, fs) in self.pos:
142
res+='<td width="%d"></td><td style="%s" width="%d">%s</td>' % (x - posx, style, pos2, txt)
145
res+='<td width="%d" align="right" style="%s">%s</td>' % (x - posx, style, txt)
148
res+='<td width="%d" align="center" style="%s">%s</td>' % ((x - posx)*2, style, txt)
156
class _rml_tmpl_draw_lines(_rml_tmpl_tag):
157
def __init__(self, node, style):
158
coord = [utils.unit_get(x) for x in utils.text_get(node).split(' ')]
162
self.width = coord[2]-coord[0]
163
self.ok = coord[1]==coord[3]
165
self.style = style.get('hr')
169
return '<table border="0" cellpadding="0" cellspacing="0" width="%d"><tr><td width="%d"></td><td><hr width="100%%" style="margin:0px; %s"></td></tr></table>' % (self.posx+self.width,self.posx,self.style)
173
class _rml_stylesheet(object):
174
def __init__(self, stylesheet, doc):
178
'fontSize': lambda x: ('font-size',str(utils.unit_get(x))+'px'),
179
'alignment': lambda x: ('text-align',str(x))
182
for ps in stylesheet.getElementsByTagName('paraStyle'):
184
attrs = ps.attributes
185
for i in range(attrs.length):
186
name = attrs.item(i).localName
187
attr[name] = ps.getAttribute(name)
191
attrs.append("%s:%s" % self._tags[a](attr[a]))
193
result += "p."+attr['name']+" {"+'; '.join(attrs)+"}\n"
199
class _rml_draw_style(object):
203
'fill': lambda x: {'td': {'color':x.getAttribute('color')}},
204
'setFont': lambda x: {'td': {'font-size':x.getAttribute('size')+'px'}},
205
'stroke': lambda x: {'hr': {'color':x.getAttribute('color')}},
207
def update(self, node):
208
if node.localName in self._styles:
209
result = self._styles[node.localName](node)
211
if key in self.style:
212
self.style[key].update(result[key])
214
self.style[key] = result[key]
215
def font_size_get(self,tag):
216
size = utils.unit_get(self.style.get('td', {}).get('font-size','16'))
220
if not tag in self.style:
222
return ';'.join(['%s:%s' % (x[0],x[1]) for x in self.style[tag].items()])
224
class _rml_template(object):
225
def __init__(self, template):
228
self.template_order = []
229
self.page_template = {}
232
'drawString': _rml_tmpl_draw_string,
233
'drawRightString': _rml_tmpl_draw_string,
234
'drawCentredString': _rml_tmpl_draw_string,
235
'lines': _rml_tmpl_draw_lines
237
self.style = _rml_draw_style()
238
for pt in template.getElementsByTagName('pageTemplate'):
240
id = pt.getAttribute('id')
241
self.template_order.append(id)
242
for tmpl in pt.getElementsByTagName('frame'):
243
posy = int(utils.unit_get(tmpl.getAttribute('y1'))) #+utils.unit_get(tmpl.getAttribute('height')))
244
posx = int(utils.unit_get(tmpl.getAttribute('x1')))
245
frames[(posy,posx,tmpl.getAttribute('id'))] = _rml_tmpl_frame(posx, utils.unit_get(tmpl.getAttribute('width')))
246
for tmpl in template.getElementsByTagName('pageGraphics'):
247
for n in tmpl.childNodes:
248
if n.nodeType==n.ELEMENT_NODE:
249
if n.localName in self._tags:
250
t = self._tags[n.localName](n, self.style)
251
frames[(t.posy,t.posx,n.localName)] = t
257
self.page_template[id] = []
258
for key in range(len(keys)):
259
if key>0 and keys[key-1][0] == keys[key][0]:
260
if type(self.page_template[id][-1]) == type(frames[keys[key]]):
261
if self.page_template[id][-1].tag_mergeable():
262
self.page_template[id][-1].merge(frames[keys[key]])
264
self.page_template[id].append(frames[keys[key]])
265
self.template = self.template_order[0]
267
def _get_style(self):
270
def set_next_template(self):
271
self.template = self.template_order[(self.template_order.index(name)+1) % self.template_order]
274
def set_template(self, name):
278
def frame_start(self):
280
frames = self.page_template[self.template]
284
if self.frame_pos>=len(frames):
289
f = frames[self.frame_pos]
290
result+=f.tag_start()
296
def frame_stop(self):
297
frames = self.page_template[self.template]
298
f = frames[self.frame_pos]
308
result += self.frame_start()
309
result += self.frame_stop()
312
class _rml_doc(object):
313
def __init__(self, data):
314
self.dom = xml.dom.minidom.parseString(data)
315
self.filename = self.dom.documentElement.getAttribute('filename')
318
def render(self, out):
319
self.result += '''<!DOCTYPE HTML PUBLIC "-//w3c//DTD HTML 4.0 Frameset//EN">
322
<style type="text/css">
323
p {margin:0px; font-size:12px;}
326
style = self.dom.documentElement.getElementsByTagName('stylesheet')[0]
327
s = _rml_stylesheet(style, self.dom)
328
self.result += s.render()
334
template = _rml_template(self.dom.documentElement.getElementsByTagName('template')[0])
335
f = _flowable(template, self.dom)
336
self.result += f.render(self.dom.documentElement.getElementsByTagName('story')[0])
338
self.result += '</body></html>'
339
out.write( self.result)
341
def parseString(data, fout=None):
349
fp = StringIO.StringIO()
354
print 'Usage: rml2html input.rml >output.html'
355
print 'Render the standard input (RML) and output an HTML file'
358
if __name__=="__main__":
360
if sys.argv[1]=='--help':
362
print parseString(file(sys.argv[1], 'r').read()),
364
print 'Usage: trml2pdf input.rml >output.pdf'
365
print 'Try \'trml2pdf --help\' for more information.'