HTML-Generator. Markup-Parser, Templates?

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
arghargh
User
Beiträge: 81
Registriert: Donnerstag 4. September 2008, 22:26

HTML-Generator. Markup-Parser, Templates?

Beitragvon arghargh » Sonntag 28. September 2008, 11:05

Ich möchte ein Programm schreiben, das Daten aus einer Verzeichnisstruktur sammelt und daraus statisches HTML baut.

Markup wie Textile oder Markdown ist ein Muß, allerdings genügt es meinen Ansprüchen nicht. D.h. ich brauche einen Parser, der leicht zu erweitern ist.
Das Ganze kann auch reines Python sein, da es nicht auf eine hohe Geschwindigkeit ankommt.

Ich stelle mir das so vor, dass ich eine Reihe von regulären Ausdrücken aufstelle, die regulär, oder mit dem Rückgabewert eines Handlers ersetzt werden.
Wahrscheinlich gibt es da noch bessere Ansätze, da habe ich keine Ahnung von.

Der zweite Punkt ist das Zusammenbauen vom HTML. Die Grundstruktur ist immer weitgehend gleich, aber ein paar Tags und vorallem der eigentliche Inhalt ändert sich natürlich.
Lohnt es sich, für eine einfache, statische Seite überhaupt, ein Templatesystem zu verwenden? Oder bin ich besser beraten, wenn ich einfach einige Strings definiere, und dann einfach zusammenbaue?
Es wäre vielleicht ganz praktisch, das Template als HTML direkt im Browser angucken zu können.

Wie immer freue ich mich über Anhaltspunkte, auf deren Basis ich meine Suche fortsetzen kann. Suchmaschinen haben keine Erfahrung! :-)
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Re: HTML-Generator. Markup-Parser, Templates?

Beitragvon Leonidas » Sonntag 28. September 2008, 11:21

arghargh hat geschrieben:Markup wie Textile oder Markdown ist ein Muß, allerdings genügt es meinen Ansprüchen nicht. D.h. ich brauche einen Parser, der leicht zu erweitern ist.

Du kannst ja die Textile oder Markdown-Parser mal ansehen und gucken ob man da was erweitern kann. Bei den docutils (reStructuredText) geht das - siehe Sphinx.

arghargh hat geschrieben:Lohnt es sich, für eine einfache, statische Seite überhaupt, ein Templatesystem zu verwenden?

Ja. Templateengines lohnen sich fast immer.

arghargh hat geschrieben:Es wäre vielleicht ganz praktisch, das Template als HTML direkt im Browser angucken zu können.

Du suchst also etwas XML-basiertes? Dann schau dir mal Genshi an.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Beitragvon Y0Gi » Sonntag 28. September 2008, 12:14

python-markdown lässt sich passabel erweitern. markdown2 ist zwar offenbar viel schneller und sauberer - Möglichkeiten der Erweiterbarkeit, die über reine Regex-basierte Erweiterung hinaus gehen (was für mich vollkommen unzureichend ist), habe ich leider nicht gefunden.
arghargh
User
Beiträge: 81
Registriert: Donnerstag 4. September 2008, 22:26

Beitragvon arghargh » Sonntag 28. September 2008, 12:25

Danke schonmal.

pyTextile gibt es wohl hier:
http://code.google.com/p/pytextile/downloads/list

textile.py hat etwa 2900 Zeilen

Tendenziell finde ich Textile besser als Markdown. Ich brauche aber sowieso nicht alle Möglichkeiten. Letztenendes werden solche Parser wohl hauptsächlich auf RegExp aufgebaut sein!?
Dann kommt es für mich auch in Frage, etwas eigenes zu machen. Nur wie? ;-)

(Rubys regular expressions sind irgendwie besser zu bedienen, oder?)
Zuletzt geändert von arghargh am Sonntag 28. September 2008, 13:27, insgesamt 1-mal geändert.
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Sonntag 28. September 2008, 12:47

arghargh hat geschrieben:(Rubys regular expressions sind irgendwie besser zu bedienen, oder?)

Inwiefern? Besser im Sinne von "können weniger"?

Was es auch nocht gibt ist Wiki-Coral, das könntest du dir auch überlegen. Oder eben reST.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
arghargh
User
Beiträge: 81
Registriert: Donnerstag 4. September 2008, 22:26

Beitragvon arghargh » Sonntag 28. September 2008, 13:26

Insofern, als dass sie als Objekt verwendet werden können und nicht erst umständlich compiled werden müssen.
Ich habe weder von Ruby noch von Python Ahnung, aber tendenziell finde ich die Python Syntax angenehmer.

Hier mal ein Vergleich:

Code: Alles auswählen

  r.gsub!(/((http|https|ftp)\S+)/i, '"\1":\1')


Code: Alles auswählen

url = re.compile('((http|https|ftp)\S+)',re.IGNORECASE)
text = url.sub(r'"\1":\1', text)


Naja, liegt wohl eher an der Funktion, nicht am Ausdruck. Es interessiert mich allerdings, ob man das re.IGNORECASE noch anders unterbringen kann. In der Doku war das kurz erwähnt, ich habe es aber nicht verstanden.

--

Jetzt habe ich gerade genshi ausprobiert, finde mich aber leider in der Dokumentation nicht zurecht.

Code: Alles auswählen

loader = TemplateLoader(['.'])
tmpl = loader.load('template.html')
outf.write(tmpl.generate(content=html).render('html', doctype='html'))


So werden bestehende Tags aus dem string content in unicode-Zeichen umgewandelt:

[code=]<h1>[/code]

Das würde ich gerne abstellen.
arghargh
User
Beiträge: 81
Registriert: Donnerstag 4. September 2008, 22:26

Beitragvon arghargh » Sonntag 28. September 2008, 13:46

Ich glaube meine Frage ist beantwortet:
http://genshi.edgewall.org/wiki/GenshiF ... lateoutput

Code: Alles auswählen

tmpl.generate(content=genshi.Markup(html)).render('xhtml', doctype='xhtml')
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Beitragvon Y0Gi » Sonntag 28. September 2008, 13:56

arghargh hat geschrieben:Letztenendes werden solche Parser wohl hauptsächlich auf RegExp aufgebaut sein!?

Solche Parser in der Regel ja, aber ich bin auch kein Parser- und Lexer-Guru.

Meine Kritik an markdown2 bezieht sich darauf, dass man als Ersetzung nur einen String mit \1-Platzhaltern angeben kann, jedoch keine Callable, in der man erweiterte Textersetzung z. B. auch mit Datenbank-Abfragen vornehmen kann.
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Sonntag 28. September 2008, 14:09

arghargh hat geschrieben:Naja, liegt wohl eher an der Funktion, nicht am Ausdruck.

Du kannst auch ``re.sub`` nehmen, wo du das Pattern als String angibst und es nicht explizit kompilieren musst. Kompilieren ist dann sinnvoll, wenn man den regulären Ausdruck mehrfach matchen will, dann muss nicht immer neu kompiliert werden.

arghargh hat geschrieben:Es interessiert mich allerdings, ob man das re.IGNORECASE noch anders unterbringen kann. In der Doku war das kurz erwähnt, ich habe es aber nicht verstanden.

Geht so:

Code: Alles auswählen

re.findall(r'abc(?i)', 'ABC')


arghargh hat geschrieben:So werden bestehende Tags aus dem string content in unicode-Zeichen umgewandelt:

[code=]<h1>[/code]

Das würde ich gerne abstellen.

Das nennt sich Autoescaping und ist generell eine gute Idee (sowohl aus der Sicherheitssicht als auch der Standardkonformitäts-Sicht). Wenn man schon fertig gerendertes HTML an Genshi ausgibt, hat man idR. etwas falsch gemacht, so garantiert Genshi wohlgeformtes HTML, aber wenn man Autoescaping abschaltet, geht das nicht mehr.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
arghargh
User
Beiträge: 81
Registriert: Donnerstag 4. September 2008, 22:26

Beitragvon arghargh » Sonntag 28. September 2008, 14:31

Wenn man schon fertig gerendertes HTML an Genshi ausgibt, hat man idR. etwas falsch gemacht,


Ich vermute, man sollte also entsprechende streams an genshi übergeben.
Wie stellt man das an? Material kommt von einem Markup-Parser wie z.B. pytextile. Ausserdem möchte ich von pygment erzeugtes HTML einbauen.
Schön wär auch noch, wenn mathematische Formeln in irgendeiner Form umgesetzt werden könnten.

Es wird immer komplizierter, dabei ist es doch so einfach! ;-)

markdown2 ... als Ersetzung ... keine Callable

Das ist natürlich schlecht.

Mal ein naiver Gedanke:
Kann man nicht eine Liste/Dictionary o.Ä. mit <regexstring>,<funktion> einfach abarbeiten und die matches an die funktion übergeben?

Oder lässt sich eine Syntax wie Textile nicht so einfach verarbeiten, wie ich mir das denke?
arghargh
User
Beiträge: 81
Registriert: Donnerstag 4. September 2008, 22:26

Beitragvon arghargh » Sonntag 28. September 2008, 17:45

Hier ist ein ausführlicher englischer Artikel, "Wiki Markup Parser in Python":
http://wiki.sheep.art.pl/Wiki%20Markup% ... n%20Python
lunar

Beitragvon lunar » Sonntag 28. September 2008, 18:22

Leonidas hat geschrieben:Wenn man schon fertig gerendertes HTML an Genshi ausgibt, hat man idR. etwas falsch gemacht, so garantiert Genshi wohlgeformtes HTML, aber wenn man Autoescaping abschaltet, geht das nicht mehr.

Darüber lässt sich jetzt trefflich streiten. Fertiges HTML an die Template-Engine zu übergeben, ist imho durchaus üblich. Ich denke da an Formgeneratoren wie wtforms oder an Markup, dass erst durch einen anderen Generator fließt, wie z.B. bei Sphinx oder Inyoka.
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Sonntag 28. September 2008, 18:32

lunar hat geschrieben:
Leonidas hat geschrieben:Wenn man schon fertig gerendertes HTML an Genshi ausgibt, hat man idR. etwas falsch gemacht, so garantiert Genshi wohlgeformtes HTML, aber wenn man Autoescaping abschaltet, geht das nicht mehr.

Darüber lässt sich jetzt trefflich streiten. Fertiges HTML an die Template-Engine zu übergeben, ist imho durchaus üblich. Ich denke da an Formgeneratoren wie wtforms oder an Markup, dass erst durch einen anderen Generator fließt, wie z.B. bei Sphinx oder Inyoka.

Ja, das stimmt - irgendwie scheint mir das aber immer noch nicht optimal zu sein. Ich habe das auch gemacht, da die Django Templates so wenig konnten also musste ich dann Tags schreiben, die HTML generiert haben. Aber so ganz optimal ist das nicht. Besser wäre es statt einen String mit HTML zu übergeben, der Templatesprache das irgendwie in struktuerierter Form zu übergeben. Also effektiv als Sub-Template, dass in den Renderingprozess des gesamten Templates aufgenommen werden kann und dadurch auch validiert werden kann. Naja :?
My god, it's full of CARs! | Leonidasvoice vs Modvoice
lunar

Beitragvon lunar » Sonntag 28. September 2008, 18:38

Naja, HTML ist standardisiert, die Doctrees und ASTs verbreiteter Template-Engines und Markupparser eher nicht. Und die Vielzahl der Parser und Template-Engines macht die Implementierung dieser Idee ein bisschen schwierig ;)
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Beitragvon sma » Montag 29. September 2008, 09:20

arghargh hat geschrieben:Insofern, als dass sie als Objekt verwendet werden können und nicht erst umständlich compiled werden müssen.

Das stimmt nicht. Der Vergleich wäre eher:

Code: Alles auswählen

text = text.gsub(/(https?\S+)/, '"\1":\1')

Code: Alles auswählen

text = re.sub(r"(https?\S+)", r'"\1":\1"', text)

Ruby ist ein bisschen kürzer und IMHO eleganter, da `gsub` eine Methode von String ist und nicht eine globale Funktion eines Moduls, aber kompilieren muss man nicht, wenn man die zusätzliche Performance nicht will.

Ansonsten hier ein Beispiel, wie man sich selbst einen Übersetzer für eigenes Markup bauen kann. Sagen wir, ich will Absätze mit Leerzeilen trennen. Ich will Aufzählungen mit "* " einleiten können und Programmcode mit 4 Leerzeichen. < und & sollen automatisch in < und & verwandelt werden.

Code: Alles auswählen

import re

def format(text):
    text = "\n".join(format_line(line) for line in text.splitlines())
    return re.sub(r"</(\w+)>\n<\1>", "\n", text)

def format_line(line):
    if line.startswith("* "): return "<ul><li>%s</li></ul>" % format_inline(line[2:])
    if line.startswith("    "): return "<pre>%s</pre>" % escape(line[4:])
    if line.strip(): return "<p>%s</p>" % format_inline(line)
    return line

def format_inline(line):
    return escape(line)

def escape(line):
    return line.replace("&", "&").replace("<", "<")


Trickreich ist einzig `format`, das zunächst jede Zeile für sich betrachtet und dann Zeilen mit gleichem Format verschmilzt. Das reicht nicht für alles, aber ist deutlich einfacher als ein echter Parser. Weitere Zeilenformate wie etwa "== " für eine Überschrift lassen sich jetzt leicht hinzufügen. Was allerdings nicht so einfach geht, ist das Verhalten von Markdown zu realisieren, bei dem man Überschriften unterstreicht.

Möchte man z.B. Code innerhalb keiner Zeile mit ` ` markieren oder etwas mit * * hervorheben, lässt sich das wie folgt realisieren. Ich muss hier aufpassen, das ich alles in ` ` nicht mehr als Markup interpretiere.

Code: Alles auswählen

def format_inline(line):
    def repl(m):
        if m.group(2):
            return "<code>%s</code>" % m.group(2).strip()
        return re.sub(r'\*(.*?)\*', r'<strong>\1</strong>', m.group(3))
    return re.sub(r"(`+)(.*?)\1|([^`]*)", repl, escape(line))


An dieser Stelle könnte man dann auch noch Dinge machen, wie " in "echte" Anführungszeichen umzuwandeln, aus "--" und "..." entsprechende Satzzeichen zu machen oder weitere Auszeichnungen zu interpretieren.

Stefan

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder