Das ist nur ein Testprojekt von mir, da hab ich mich nur mit der XML Syntax und dem Parsern derjenigen auseinandergesetzt.
Aber vielleicht kann ja einer was daraus lernen ^^
colubra.py
Code: Alles auswählen
# -*- coding: utf-8 -*-
from xml.parsers import expat
from xml.sax import saxutils
class PythonWriter:
one_line_tags = ['img', 'hr', 'br', 'meta', 'link']
def __init__(self):
self.doc = []
self.level = 2
self.outdent_tags = []
self.level_indention = ' '
def header(self):
header_data = [
(0, '# -*- coding: utf-8'),
(0, 'try:'),
(1, 'from cStringIO import StringIO'),
(0, 'except:'),
(1, 'from StringIO import StringIO'),
(0, 'from xml.sax import saxutils'),
(0, ''),
(0, 'class CulebraTemplate:'),
(1, 'def __init__(self, namespace, output=None):'),
(2, 'self.__namespace = namespace'),
(2, 'self.__do_output = False'),
(2, 'if output is None:'),
(3, 'self.__result = StringIO()'),
(3, 'self.__do_output = True'),
(2, 'else:'),
(3, 'self.__result = output'),
(1, ''),
(1, 'def __call__(self):'),
(2, 'self.__run__()'),
(2, 'if self.__do_output:'),
(3, 'return self.__result.getvalue()'),
(1, ''),
(1, 'def __run__(self):'),
(2, 'for key in self.__namespace:'),
(3, 'globals()[key] = self.__namespace[key]'),
(2, 'try: del key'),
(2, 'except NameError: pass')
]
for line in header_data:
self.doc.append(line)
def translate_var(self, var):
parts = str(var).split('.')
result = parts[0]
for part in parts[1:]:
result += '[\'%s\']' % part.encode('string-escape')
return result
def write_line(self, data):
data = str(data).encode('string-escape')
self.doc.append((self.level, 'self.__result.write(\'%s\')' % data))
def write_var(self, data):
var = self.translate_var(data)
strvar = '{%s}' % str(data).encode('string-escape')
self.doc.append((self.level, 'try:'))
self.doc.append((self.level + 1, 'self.__result.write(%s)' % var))
self.doc.append((self.level, 'except:'))
self.doc.append((self.level + 1, 'self.__result.write(\'%s\')' % strvar))
def write_var_quoted(self, data):
var = self.translate_var(data)
strvar = saxutils.quoteattr('{%s}' % str(data).encode('string-escape'))
self.doc.append((self.level, 'try:'))
self.doc.append((self.level + 1, 'self.__result.write(saxutils.quoteattr(%s))' % var))
self.doc.append((self.level, 'except:'))
self.doc.append((self.level + 1, 'self.__result.write(\'%s\')' % strvar))
def write_replace(self, variables, data):
data = str(data).encode('string-escape')
self.doc.append((self.level, '__tmp_output = \'%s\'' % data))
self.doc.append((self.level, '__replacement_table = {'))
for var in variables.split(','):
p = var.split(' with ', 1)
if len(p) == 1:
_search = str(p[0].strip()).encode('string-escape')
_replace = self.translate_var(p[0].strip())
else:
_search = str(p[0].strip()).encode('string-escape')
_replace = self.translate_var(p[1].strip())
self.doc.append((self.level + 1, '\'%s\': %s,' % (_search, _replace)))
self.doc.append((self.level, '}'))
self.doc.append((self.level, 'for __search, __replace in __replacement_table.items():'))
self.doc.append((self.level + 1, '__tmp_output = __tmp_output.replace(\'$%s\', __replacement_table[\'%s\'])' % (_search, _search)))
self.doc.append((self.level, 'self.__result.write(__tmp_output)'))
def write_tag(self, name, attributes):
if 'py:if' in attributes:
self.doc.append((self.level, 'if %s:' % attributes['py:if'].strip()))
del attributes['py:if']
self.outdent_tags.append(name)
self.level += 1
self.write_line('<' + name)
py_for = False
if 'py:for' in attributes:
py_for = attributes['py:for']
if 'py:attrib' in attributes:
replaces = attributes['py:attrib'].split(',')
for item in replaces:
p = item.split(' as ', 1)
_var = p[0].strip()
_as = p[1].strip()
self.write_line(' %s=' % _as)
self.write_var_quoted(_var)
if _as in attributes:
del attributes[_as]
del attributes['py:attrib']
for key in attributes:
self.write_line(' %s=%s' % (key, saxutils.quoteattr(attributes[key])))
if name in self.one_line_tags:
self.write_line(' />')
else:
self.write_line('>')
if py_for:
p = py_for.split(' as ')
_as = p[1].strip()
_var = p[0].strip()
self.doc.append((self.level, 'for %s in %s:' % (_as, _var)))
self.outdent_tags.append(name)
self.level += 1
def write_end_tag(self, name):
try:
last = self.outdent_tags[-1]
if last == name:
self.outdent_tags.pop()
self.level -= 1
except IndexError:
pass
if not name in self.one_line_tags:
self.write_line('</%s>' % name)
def get_data(self):
result = ''
for indent, line in self.doc:
result += self.level_indention * indent + line.strip() + '\n'
return result
class Parser:
def __init__(self, template):
self.parser = expat.ParserCreate()
self.parser.StartElementHandler = self.start_element
self.parser.EndElementHandler = self.end_element
self.parser.CharacterDataHandler = self.cdata
self.compiler = None
self.template = template
self.cdata_mod = None
def start_element(self, name, attrs):
if 'py:insert' in attrs:
self.cdata_mod = ('insert', attrs['py:insert'])
del attrs['py:insert']
elif 'py:replace' in attrs:
self.cdata_mod = ('replace', attrs['py:replace'])
del attrs['py:replace']
self.compiler.write_tag(name, attrs)
def end_element(self, name):
self.compiler.write_end_tag(name)
def cdata(self, data):
if not self.cdata_mod is None:
if self.cdata_mod[0] == 'insert':
self.compiler.write_var(self.cdata_mod[1])
if self.cdata_mod[0] == 'replace':
self.compiler.write_replace(self.cdata_mod[1], data)
self.cdata_mod = None
else:
self.compiler.write_line(data)
def parse(self):
self.compiler = PythonWriter()
self.compiler.header()
self.parser.Parse(self.template)
return self.compiler.get_data()
###############################################################################
# Simple Access
def parse(filename):
t = file(filename + '.xml').read()
p = Parser(t)
return p.parse()
def compile(filename):
import os
import py_compile
code = parse(filename)
filename += '.py'
file(filename, 'w').write(code)
py_compile.compile(filename)
os.unlink(filename)
def execute(filename, namespace):
try:
module = __import__(filename, locals(), globals(), ['CulebraTemplate'])
except ImportError:
compile(filename)
module = __import__(filename, locals(), globals(), ['CulebraTemplate'])
return module.CulebraTemplate(namespace)()
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import culebra
namespace = {
'page': {
'title': 'Demonstation Page'
},
'navigation': [
{'href': '#', 'title': 'current page'},
{'href': 'index.html', 'title': 'overview'},
{'href': 'about.html', 'title': 'about'}
]
}
print culebra.execute('demo', namespace)
Code: Alles auswählen
<?xml version="1.0" encoding="utf-8"?>
<html>
<head>
<title py:replace="title with page.title">CulebraDemoTemplate :: $title</title>
</head>
<body>
<h1 py:insert="page.title">%s</h1>
<ul py:for="navigation as item">
<li><a py:attrib="item.href as href, item.title as title" py:insert="item.title">%s</a></li>
</ul>
<div id="footer" py:insert="footer">%s</div>
</body>
</html>
Code: Alles auswählen
<html>
<head>
<title>CulebraDemoTemplate :: Demonstation Page</title>
</head>
<body>
<h1>Demonstation Page</h1>
<ul>
<li><a href="#" title="current page">current page</a></li>
<li><a href="index.html" title="overview">overview</a></li>
<li><a href="about.html" title="about">about</a></li>
</ul>
<div id="footer">{footer}</div>
</body>
</html>