#! /usr/bin/python import re, sys keywords = 'end', 'template', 'if', 'elif', 'else', 'apply-template', 'include' _varname = re.compile('%{(\w+)}') _meta = re.compile('^\s*\s*$' % '|'.join(keywords)) _templates = {} class THtml: def __init__(self, src): self._liter = iter(src) def begin(self, dct): try: while self.recv(self._liter.next(), dct): pass except StopIteration: pass return self._liter def recv(self, line, dct): key, exp = _G_meta(line) if key: return self.statement(key, exp, dct) return self.normal(line, dct) def statement(self, key, exp, dct): if key == 'if': exp = eval(_G_repl(exp[:exp.rindex(':')], dct)) self._liter = If(exp, self._liter).begin(dct) elif key == 'template': exp = eval(_G_repl(exp[:exp.rindex(':')], dct)) txt = [] self._liter = Extract(self._liter, txt).begin(dct) txt.pop() _templates[exp] = txt elif key == 'include': exp = eval(_G_repl(exp, dct)) THtml(file(exp).readlines()).begin(dct) elif key == 'apply-template': exp = eval(_G_repl(exp, dct)) tval = dct.get(exp, {}) if type(tval) == list: for d in tval: THtml(_templates.get(exp, [])).begin(d) elif type(tval) == dict: THtml(_templates.get(exp, [])).begin(tval) elif tval != None: raise ValueError, "'%s': type of '{}/[{}*]' expected" % exp else: assert 0, 'Unknown keyword: ' + key return 1 def normal(self, line, dct): sys.stdout.write(_G_repl(line, dct)) return 1 class Skip(THtml): def __init__(self, src): THtml.__init__(self, src) def statement(self, key, exp, dct): if key == 'end': return 0 elif key in ('if', 'template'): self._liter = Skip(self._liter).begin(dct) return 1 def normal(self, line, dct): return 1 class Extract(THtml): def __init__(self, src, lines): THtml.__init__(self, src) self._lines = lines def recv(self, line, dct): self._lines.append(line) return THtml.recv(self, line, dct) def statement(self, key, exp, dct): if key == 'end': return 0 elif key in ('if', 'template'): self._liter = Extract(self._liter, self._lines).begin(dct) return 1 def normal(self, line, dct): return 1 class If(THtml): def __init__(self, bool, src): THtml.__init__(self, src) self._true = bool def statement(self, key, exp, dct): if key == 'end': return 0 elif key in ('elif', 'else'): if self._true: self._liter = Skip(self._liter).begin(dct) else: if key == 'elif': self._true = eval(_G_repl((exp[: exp.rindex(':')]), dct)) else: self._true = 1 else: if self._true: return THtml.statement(self, key, exp, dct) elif key in ('if', 'template'): self._liter = Skip(self._liter).begin(dct) return 1 def normal(self, line, dct): if self._true: THtml.normal(self, line, dct) return 1 def _G_repl(txt, dct): return re.sub(_varname, lambda g: str(dct.get(g.group(1))), txt) def _G_meta(line): res = re.search(_meta, line) if res: return res.group(1, 2) return 0, 0 def fprintf(outf, filename, glob): bak, sys.stdout = sys.stdout, outf printf(filename, glob) sys.stdout = bak def printf(inf, glob): if type(inf) == str: inf = file(inf) THtml(inf).begin(glob) import os def test(): from StringIO import StringIO content = """\ %{name} %{sex} %{age} %{subject} %{score} %{name} %{age} %{inc_file} %{city} """ def test_data(): data = """\ Xiaoyu * female * 20 * english 80 maths 88 chinese 92 * song 44 yang 45 * Beijing * () wu * male * 20 * c/c++ 8 maths 8 listening 9 * wu 4 wei 5 * ShenZhen * () """ glob = [] for line in data.splitlines(): h = {} v = [x.strip() for x in line.rstrip().split('*')][:-1] h['name'], h['sex'], h['age'], result_exam, family, h['city'] = v h['result_exam'] = [{None: None}] if result_exam: r = result_exam.split() while r: t = {} t['score'], t['subject'] = r.pop(), r.pop() h['result_exam'].append(t) h['family'] = [] if family: r = family.split() while r: t = { 'inc_file' : 'family.inc' } t['age'], t['name'] = r.pop(), r.pop() h['family'].append(t) glob.append(h) return glob glob = test_data() try: fprintf(sys.stdout, StringIO(content).readlines(), { 'glob' : glob }) except Exception, e: print 'Error:', e if __name__ == '__main__': test()