Colubra XML Template

Code-Stücke können hier veröffentlicht werden.
Benutzeravatar
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Colubra XML Template

Beitragvon mitsuhiko » 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

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)()


test.py

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)


demo.xml

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>


Ausgabe sieht dann etwa so aus:

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>
Zuletzt geändert von mitsuhiko am Freitag 9. Dezember 2005, 15:25, insgesamt 1-mal geändert.
TUFKAB – the user formerly known as blackbird
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Donnerstag 17. November 2005, 21:28

Was soll dass denn werden? Eine Kid-ähnliches Templetingsystem?
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Beitragvon mitsuhiko » Donnerstag 17. November 2005, 21:34

Leonidas hat geschrieben:Was soll dass denn werden? Eine Kid-ähnliches Templetingsystem?


Das soll gar nichts werden. Ich wollte mich mit Expat auseinandersetzen und das ist rausgekommen. Deswegen poste ich es ja in Codesnippets und nicht im Showcase :wink:
TUFKAB – the user formerly known as blackbird
Benutzeravatar
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Beitragvon mitsuhiko » Donnerstag 17. November 2005, 22:44

ARGH. das syntax highlighting macht den code kaputt. Wers testen will:
1.) beitrag quoten
2.) eintrag rauskopieren
3.) ein datei einfügen
:wink:
TUFKAB – the user formerly known as blackbird
Benutzeravatar
jens
Moderator
Beiträge: 8458
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Beitragvon jens » Freitag 18. November 2005, 08:36

Sieht für mich wie eine Mischung aus simpleTAL mit SpyTee aus ;)

Wenn du dich mit Templating auseinander setzt, solltest du dir auf jeden Fall mal simpleTAL anschauen!

Hier ein paar Links, die du vielleicht schon kennst:
http://www.python-forum.de/viewtopic.php?t=4323
http://www.python-forum.de/viewtopic.php?t=4242
http://www.python-forum.de/viewtopic.php?t=4256
http://www.python-forum.de/viewtopic.php?t=4231

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Beitragvon mitsuhiko » Freitag 18. November 2005, 16:16

jens hat geschrieben:Sieht für mich wie eine Mischung aus simpleTAL mit SpyTee aus ;)

Wenn du dich mit Templating auseinander setzt, solltest du dir auf jeden Fall mal simpleTAL anschauen!


verzichte, dass war nur ein Test ^^
Momentan schreib ich an einem Python 2 Javascript Konverter.
TUFKAB – the user formerly known as blackbird
Benutzeravatar
jens
Moderator
Beiträge: 8458
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Beitragvon jens » Freitag 18. November 2005, 16:20

blackbird hat geschrieben:Momentan schreib ich an einem Python 2 Javascript Konverter.

Hm! Da bin ich ja mal gespannt! Ich nehme an für AJAX???

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Freitag 18. November 2005, 16:35

Wie wärs mit CrackAJAX?
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Beitragvon mitsuhiko » Freitag 18. November 2005, 16:37

Leonidas hat geschrieben:Wie wärs mit CrackAJAX?


AHHHHHHHHHHHHHHHHHHHHHHHHHHHHH.
Warum erfahre ich erst jetzt davon? Na egal. Ich bin eh schon weiter :)
TUFKAB – the user formerly known as blackbird
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Freitag 18. November 2005, 18:07

blackbird hat geschrieben:Warum erfahre ich erst jetzt davon?

Zu wenig Daily Python URL gelesen? :wink:

Dein Projekt ist schon interessant, so habe ich auch nicht wirklich Lust JavsScript selbst zu schreiben, auch nicht mit MochiKit.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Beitragvon mitsuhiko » Freitag 18. November 2005, 19:56

Leonidas hat geschrieben:Dein Projekt ist schon interessant, so habe ich auch nicht wirklich Lust JavsScript selbst zu schreiben, auch nicht mit MochiKit.


Deswegen hab ich ja damit angefangen. Aber zuerst wollte ich nur eine javascript bridge zu python funktionen machen. Gestern musste ich dann ein pyc compilieren und habe durch zufall compiler.ast gefunden.
Dann lag das schon fast auf der Hand :-)

Der Parser ist jetzt fertig, ich lege jetzt noch die python objekte als javascript objekte ab. Momentan ist aber nur String zu 70% fertig und einige builtin functionen wie len() und so.
TUFKAB – the user formerly known as blackbird

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder