Colubra XML Template
Verfasst: Donnerstag 17. November 2005, 21:25
Zu allererst. NICHT VERWENDEN.
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
test.py
demo.xml
Ausgabe sieht dann etwa so aus:
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>