#!/usr/bin/python # -*- coding: utf-8 -*- # Copyright (C) 2013 Étienne Loks # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # This program 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 Affero General Public License for more details. # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # See the file COPYING for details. import locale, re from zipfile import ZipFile, ZIP_DEFLATED from cStringIO import StringIO from xml.etree.cElementTree import ElementTree, fromstring from django.conf import settings OOO_NS = "{urn:oasis:names:tc:opendocument:xmlns:text:1.0}" def _set_value_from_formula(value, context, default_value): value = value.strip() if value.startswith("ooow:") and len(value) >= 5: value = value[5:] if value.startswith('"') and value.endswith('"') and len(value) > 1: value = value[1:-1] elif value in context: value = _format_value(context[value], default_value) else: value = None return value def _parse_condition(condition, context, default_value): # parse only == and != operator operator = "" if "!=" in condition: operator = "!=" elif "==" in condition: operator = "==" else: return var1, var2 = condition.split(operator) var1 = _set_value_from_formula(var1, context, default_value) var2 = _set_value_from_formula(var2, context, default_value) res = var1 == var2 if operator == '!=': res = not res return res def _format_value(value, default_value): if hasattr(value, 'strftime'): c_locale = settings.LANGUAGE_CODE.split('-') if len(c_locale) == 2: c_locale[1] = c_locale[1].upper() c_locale = "_".join(c_locale) if locale.getlocale()[0] != c_locale: for loc in (c_locale, c_locale+'.utf8'): try: locale.setlocale(locale.LC_ALL, loc) break except: pass try: if settings.DATE_FORMAT: value = value.strftime(settings.DATE_FORMAT).lower() else: value = value.strftime('%x') except ValueError: value = unicode(value) if locale.getlocale()[1]: value = value.decode(locale.getlocale()[1]) value = unicode(value) if value else default_value return value VAR_EXPR = u"###VAR %s###" RE_VAR = re.compile(u"###VAR %s###" % u"([-a-zA-Z0-9_]+)") IF_EXPR = u"###IF %s###(.*)###ENDIF###" RE_IF = re.compile(IF_EXPR % u"([-a-zA-Z0-9_]+)") def _ishtar_parsing(context, value): """ ###VAR nom_var### for displaying a variable name ###IF nom_var### ###ENDIF### for conditionnal display Be carreful nested condition are not yet managed! """ for key, val in RE_IF.findall(value): v = "" if key in context and context[key]: v = _ishtar_parsing(context, val) value = re.sub(IF_EXPR % key, v, value) for key in RE_VAR.findall(value): v = "" if key in context and context[key]: v = unicode(context[key]) value = re.sub(VAR_EXPR % key, v, value) return value def ooo_replace(infile, outfile, context, default_value=''): inzip = ZipFile(infile, 'r', ZIP_DEFLATED) outzip = ZipFile(outfile, 'w', ZIP_DEFLATED) # regular ooo parsing content = ElementTree(fromstring(inzip.read('content.xml'))) missing_keys = set() for xp in ('variable-set', 'variable-get'): for p in content.findall(".//"+OOO_NS+xp): name = p.get(OOO_NS+"name") if name in context: value = context[name] p.text = _format_value(value, default_value) else: if default_value != None: p.text = default_value missing_keys.add(name) for p in content.findall(".//"+OOO_NS+"conditional-text"): condition = p.get(OOO_NS+"condition") res = 'true' if _parse_condition(condition, context, default_value) \ else 'false' value = p.get(OOO_NS+'string-value-if-' + res) value = _format_value(value, default_value) if value.strip() in context: value = context[value.strip()] p.text = value # raw content parsing str_io = StringIO() content.write(str_io) value = str_io.getvalue() value = _ishtar_parsing(context, value).encode('utf-8') for f in inzip.infolist(): if f.filename == 'content.xml': outzip.writestr('content.xml', value) else: outzip.writestr(f, inzip.read(f.filename)) inzip.close() outzip.close() return missing_keys if __name__ == '__main__': infile = "../archaeological_files/tests/AR_dossier_DRAC_modele_ishtar_1-MOD.odt" outfile = "../archaeological_files/tests/AR_dossier_DRAC_modele_ishtar-test.odt" rep = {"file_incharge_surname":u"Yann", "file_incharge_name":u"Le Jeune", "fileact_ref":u"ref"} ooo_replace(infile, outfile, rep, default_value="")