root/relatorio/templates/odt.py @ 1:da857f61c615

Revision 1:da857f61c615, 5.9 kB (checked in by Nicolas Evrard <nicoe@…>, 5 years ago)

- renamed mimetypes to templates

Line 
1###############################################################################
2#
3# Copyright (c) 2007, 2008 OpenHex SPRL. (http://openhex.com) All Rights
4# Reserved.
5#
6# This program is free software; you can redistribute it and/or modify it under
7# the terms of the GNU General Public License as published by the Free Software
8# Foundation; either version 2 of the License, or (at your option) any later
9# version.
10#
11# This program is distributed in the hope that it will be useful, but WITHOUT
12# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14# details.
15#
16# You should have received a copy of the GNU General Public License along with
17# this program.  If not, see <http://www.gnu.org/licenses/>.
18#
19###############################################################################
20
21__revision__ = "$Id: odt.py 2 2008-07-04 15:49:31Z nicoe $"
22__metaclass__ = type
23
24import os
25import re
26import zipfile
27from cStringIO import StringIO
28
29import lxml.etree
30from genshi.template import Template as GenshiTemplate, MarkupTemplate
31
32NS = {'text': 'urn:oasis:names:tc:opendocument:xmlns:text:1.0',
33      'table': 'urn:oasis:names:tc:opendocument:xmlns:table:1.0',
34      'py': 'http://genshi.edgewall.org/',
35      }
36GENSHI_TAGS = re.compile(r'<(/)?(for|choose|otherwise|when|if|with)( (\w+)="(.*)"|)>')
37
38
39class Template(GenshiTemplate):
40
41    def __init__(self, source, filepath=None, filename=None, loader=None,
42                 encoding=None, lookup='strict', allow_exec=True):
43        inzip = zipfile.ZipFile(filepath)
44        content = inzip.read('content.xml')
45        inzip.close()
46        self.content_template = MarkupTemplate(self.add_directives(content))
47        super(Template, self).__init__(source, filepath, filename, loader,
48                                       encoding, lookup, allow_exec)
49
50    def _parse(self, source, encoding):
51        pass
52
53    def _prepare(self, stream):
54        return []
55
56    def add_directives(self, content):
57        tree = lxml.etree.parse(StringIO(content))
58        root = tree.getroot()
59
60        # First we create the list of all the placeholders nodes.
61        # If this is node matches a genshi directive it is put apart for
62        # further processing.
63        genshi_directives, placeholders = [], []
64        for statement in tree.xpath('//text:placeholder', namespaces=NS):
65            match_obj = GENSHI_TAGS.match(statement.text)
66            if match_obj is not None:
67                genshi_directives.append(statement)
68            placeholders.append((statement, match_obj))
69
70        # Then we match the opening and closing directives together
71        idx = 0
72        genshi_pairs, inserted = [], []
73        for statement in genshi_directives:
74            if not statement.text.startswith('</'):
75                genshi_pairs.append([statement, None])
76                inserted.append(idx)
77                idx += 1
78            else:
79                genshi_pairs[inserted.pop()][1] = statement
80
81        for p, match_obj in placeholders:
82            if match_obj is not None:
83                c_dir, directive, _, attr, a_val = match_obj.groups()
84            else:
85                c_dir, directive, _, attr, a_val = (None, p.text[1:-1], None,
86                                                    None, None)
87
88            if p in genshi_directives:
89                # If the placeholder is a for statement:
90                #    - we operate only on opening statement
91                #    - we find the nearest ancestor of the closing and opening
92                #      statement
93                #    - we create a <py:for> node
94                #    - we add all the node between the opening and closing
95                #      statements to this new node
96                #    - we replace the opening statement by the <py:for> node
97                #    - we delete the closing statement
98
99                if c_dir is not None:
100                    continue
101                for pair in genshi_pairs:
102                    if pair[0] == p:
103                        break
104                opening, closing = pair
105
106                o_ancestors = list(opening.iterancestors())
107                c_ancestors = list(closing.iterancestors())
108                for n in o_ancestors:
109                    if n in c_ancestors:
110                        ancestor = n
111                        break
112
113                genshi_node = lxml.etree.Element('{%s}%s' % (NS['py'],
114                                                             directive),
115                                                 attrib={attr: a_val},
116                                                 nsmap=NS)
117                can_append = False
118                for node in ancestor.iterchildren():
119                    if node in o_ancestors:
120                        outermost_o_ancestor = node
121                        can_append = True
122                        continue
123                    if node in c_ancestors:
124                        outermost_c_ancestor = node
125                        break
126                    if can_append:
127                        genshi_node.append(node)
128                ancestor.replace(outermost_o_ancestor, genshi_node)
129                ancestor.remove(outermost_c_ancestor)
130            else:
131                p.attrib['{%s}replace' % NS['py']] = directive
132        return lxml.etree.tostring(tree)
133
134    def generate(self, *args, **kwargs):
135        content = str(self.content_template.generate(*args, **kwargs))
136        new_oo = StringIO()
137        inzip = zipfile.ZipFile(self.filepath)
138        outzip = zipfile.ZipFile(new_oo, 'w')
139
140        for f in inzip.infolist():
141            if f.filename == 'content.xml':
142                s = StringIO()
143                s.write(str(content))
144                outzip.writestr('content.xml', s.getvalue())
145            else:
146                outzip.writestr(f, inzip.read(f.filename))
147        inzip.close()
148        outzip.close()
149
150        return new_oo.getvalue()
Note: See TracBrowser for help on using the browser.