eingene filter in Cheetah

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Lonestar
User
Beiträge: 147
Registriert: Samstag 9. August 2008, 08:31

Moin, da bin ich mal wieder.
Ich versuche schon seit etwas längerer Zeit ein Problem zu lösen und habe anscheinend einfach ein Brett vorm Kopf. Ich versuche mit Hilfe von Cheetah eine XML-Datei zu generieren. Das klappt eigentlich auch wenn ich nicht 2 Sonderwünsche hätte das encoding soll utf8 sein - es werden auch Unicodeobjekte durch meine verwendeten Variablen eingefügt. und es sollen auch Sonderzeichen wie ``& < >`` möglich sein. Eigentlich gibt es ja für sowas die Filter die ich benutzen kann.
Benutzte ich in meiner Templatedatei

Code: Alles auswählen

#filter EncodeUnicode
<?xml version="1.0" encoding="utf-8" ?>
<results>
  #for $name in $names
  <rs info="$name.id">$name.name</rs>
  #end for
</results>
#end filter
bekomme ich alle Zeichen als Unicode eingesetzt und das ganze klappt. Benutzte ich als Filter WebSafe - dann kommen die Sonderzeichen richtig rüber. Aber wie baue ich mir einen Filter der beides Kann? Beide Filter gleichzeitig benutzen funktioniert ja nicht...


EDIT by Gerold: Code-Tag auf XML umgestellt
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hallo Lonestar!

Irgendwie habe ich nicht verstanden, was das Ergebnis sein soll. Also vermute ich mal frei heraus, dass das Ergebnis so aussehen sollte:

Code: Alles auswählen

<?xml version="1.0" encoding="utf-8" ?>
<results>
  <rs info="1">Gerhard <>& ü</rs>
  <rs info="2">Markus ä</rs>
</results>
Und das bekommt man mit diesem Code in eine Datei gespeichert:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

from Cheetah.Template import Template


templatestring = \
u"""#filter WebSafe
<?xml version="1.0" encoding="utf-8" ?>
<results>
  #for $name in $names
  <rs info="$name.id">$name.name</rs>
  #end for
</results>
#end filter"""

template = Template(templatestring)
template.names = [
    {"id": 1, "name": u"Gerhard <>& ü"},
    {"id": 2, "name": u"Markus ä"},
]
unicodestring = unicode(template)

f = file("hallo.xml", "w")
f.write(unicodestring.encode("utf-8"))
f.close()
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Lonestar
User
Beiträge: 147
Registriert: Samstag 9. August 2008, 08:31

moin Gerold,
ja du hast das schon ganz richtig angenommen - die Variablen die ich in die XML-Datei einbinen möchte sollen Sonderzeichen und Unicodezeichen beinhalten. Was soll ich sagen? Dein Beispiel funktioniert - und so konnte ichs auch bei mir umsetzen. Obwohl ich mal testweise was ähnliches probiert hatte. Allerdings muss ich irgendwas falsch gemacht haben bei meiner Variante denn bei mir lief das nicht. Da ich mit encodings und speziell Unicodeobjekten immer wieder auf die Nase falle (auf meinem guten alten C64 gabs das einfach noch nicht... manchmal vermisse ich den schon :roll: ) und um noch einmal sicher zu gehen das ich deine Variante richtig verstanden habe Frage ich einfach noch mal nach:

Ich lese die Templates mit Cheetah aus einer Datei ein - nennen wir sie xml_test.tmpl. Die Datei wird auch in UTF-8 abgespeichert und sieht im ganzen jetzt ungefähr so aus:

Code: Alles auswählen

#encoding UTF-8
#filter WebSafe
<?xml version="1.0" encoding="utf-8" ?>
<results>
  #for $name in $names
  <rs  info="$name.id">$name.name</rs>
  #end for
</results>
#end filter
Aufgerufen werden die Templates bei mir folgendermaßen (die werden über CherryPy ausgeliefert - aber das is ja prinzipiell egal)

Code: Alles auswählen

filename = os.path.join(APPDIR, TEMPLATESDIR, "xml_test.tmpl ")
template = Template(file = filename)
template.names = self.db.get_names(query)
cherrypy.response.headers['Content-Type'] = "text/xml"
return unicode(template).encode('utf-8')
``names`` ist eine Liste die aus einer Datenbank geholt wird - darin sind Dictionarys mit Unicodeobjekten. Wenn ich das soweit richtig verstanden habe dann werden die Unicodeobjekte von Cheetah jetzt durch den Filter ``WebSafe`` geschickt und dann als Unicodeobjekte in das Templtate eingefügt.
Und jetzt kommt das wo ich mir nicht mehr ganz sicher bin...
``return unicode(template).encode('utf-8')``
ich mache aus meinem Template ein Unicodeobjekt gebe das encoding an (da es sonst als ascii interpretiert werden würde) und reiche das so erstellte Unicodeobjekt weiter?
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hallo Lonestar!

So wie du es machst, ist es vollkommen richtig. Du hast eine Cheetah-Vorlage, die im UTF-8-Encoding (=Bytestring) abgespeichert ist. Durch die Anweisung ``#encoding UTF-8`` (EDIT: siehe Zusatzbemerkung am Ende dieser Seite) weiß Cheetah, dass es sich hier um eine Datei handelt, die Text im UTF-8-Encoding (=Bytestring) enthält.

Beim Einlesen dieser Datei wandelt Cheetah diesen Bytestring in einen Unicodestring um.

Dann verbindest du die (Unicode-)Template mit Daten, die ebenfalls Unicode sind.

Damit dieser Unicodestring nicht unbeabsichtigt wieder in einen Bytestring umgewandelt wird, verwendest du den Befehl ``unicode()`` um das Template zu rendern. Das Ergebnis ist ein gerendertes Template als Unicodestring.

Die Verarbeitung des Textes innerhalb deines Python-Programmes findet also gänzlich mit Unicodestrings statt. Das ist genau richtig so und die ideale Basis.

Ganz zum Schluss verlässt der Text dein Programm wieder. Der Text wird an CherryPy übergeben, damit es den Text ausliefern kann. Da der Browser aber nichts mit dem Unicodestring von Python anfangen kann, muss der Unicodestring wieder in einen Bytestring umgewandelt werden. Beim Umwandeln wird angegeben, dass dafür UTF-8 als Bytestring-Encoding verwendet werden soll. Das Umwandeln übernimmt der Befehl ``encode()``.

Code: Alles auswählen

UTF-8-Bytestring --> Unicodestring --> UTF-8-Bytestring
mfg
Gerold
:-)


EDIT: ACHTUNG! Das mit ``#encoding utf-8`` ist QUATSCH. Stattdessen muss ``#unicode utf-8`` verwendet werden.


.
Zuletzt geändert von gerold am Mittwoch 18. Februar 2009, 11:45, insgesamt 1-mal geändert.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Lonestar
User
Beiträge: 147
Registriert: Samstag 9. August 2008, 08:31

Ich befürchte irgendetwas mache ich immer noch falsch...
einfach um es endlich zu kapieren habe ich mir nun eine ganz einfach Templateseite erstellt die da folgendermaßen auschaut:

Code: Alles auswählen

#encoding UTF-8 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" >
<TITLE>unicodetest</TITLE>
</HEAD>
<BODY>
    $unicodetest <br />
    Eine einfache Seite um einige Tests mit Cheetah auszuprobieren
</BODY>
</HTML>
Die Datei ist auch mit Unicode Encoding abgespeichert (zumindest sagen das UltraEdit und Editra). Aufgerufen und an über Cherrypy übergeben wird das Template aus Python heraus folgendermaßen

Code: Alles auswählen

filename = os.path.join(APPDIR, TEMPLATESDIR, "site1.tmpl")
template = Template(file = filename)
template.unicodetest = u"äöü"
return unicode(template).encode("utf-8")
Genau so funktioniert es auch. Die unicode Zeichenkette ``template.unicodetest`` wird so in das Dokument geschrieben wie erwartet.
Gehe ich aber nun hin und füge noch einen Umlaut in die Templatedatei ein - bekomme ich im Browser einen 500 Internal Server Error von Cheetah angezeigt - Der dazugehörige Traceback:

Code: Alles auswählen

Traceback (most recent call last):
  File "e:\programme\python2_5\lib\site-packages\CherryPy-3.1.1-py2.5-win32.egg\cherrypy\_cprequest.py", line 606, in respond
    cherrypy.response.body = self.handler()
  File "e:\programme\python2_5\lib\site-packages\CherryPy-3.1.1-py2.5-win32.egg\cherrypy\_cpdispatch.py", line 25, in __call__
    return self.callable(*self.args, **self.kwargs)
  File "E:\www\homepage\main.py", line 143, in site1
    return unicode(template).encode("utf-8")
  File "e:\programme\python2_5\lib\site-packages\cheetah-2.0.1-py2.5.egg\Cheetah\Template.py", line 982, in __str__
    def __str__(self): return getattr(self, mainMethName)()
  File "cheetah__www_homepage_templates_site1_tmpl_1234950942_47_88346.py", line 104, in respond
  File "e:\programme\python2_5\lib\site-packages\cheetah-2.0.1-py2.5.egg\Cheetah\DummyTransaction.py", line 32, in getvalue
    return ''.join(outputChunks)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 75: ordinal not in range(128)
wo ist denn hier mein Denkfehler? Für mich sieht das so aus als würde der feste Inhalt der Templatedatei nicht als Unicode eingelesen werden. Denn wenn ich das ganze ohne Unicode versuche ``template.unicodetest`` wird in einem normalen String geändert und der rückgabewert wird zu ``return str(template)`` bekomme ich die Seite wieder ohne Fehler ausgeliefert ... allerdings kann ich keine Unicodeobjekte mehr übergeben - die führen zu einem Fehler.
ich stehe mit encodings irgendwie auf Kriegsfuss - wäre nett wenn mir dabei auch noch geholfen werden könnte
Sebastian
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Sorry Lonestar!

Ich habe die Direktiven verwechselt. Statt ``#encoding utf-8`` muss in der Cheetah-Vorlage ``#unicode utf-8`` stehen, damit Cheetah Unicode zurück liefert.

Siehe http://www.cheetahtemplate.org/docs/CHANGES

Tausche die Direktiven aus. Dann funktioniert es.

Und noch etwas: Die Aussage
Die Datei ist auch mit Unicode Encoding abgespeichert (zumindest sagen das UltraEdit und Editra).
kann so nicht stimmen.
Die Datei ist im Encoding UTF-8 abgespeichert. Und das ist kein Unicodestring sondern ein Bytestring. Unicode verwendest du nur Python-intern.

mfg
Gerold
:-)


PS: CherryPy kann auch automatisch UTF-8 ausliefern. Dann spart man sich das explizite Umwandeln.
http://www.python-forum.de/post-85752.html#85752

.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Lonestar
User
Beiträge: 147
Registriert: Samstag 9. August 2008, 08:31

Jay! - es läuft :twisted: ich hab mal gleich einige Templates geändert. Aber das man für das passende Encoding ``#unicode utf-8`` schreiben soll hätten die auch mal ruhig in dir Doku vermerken können in der ich immer getöbert habe - da stehts auch noch mit der alten Variante... egal es läuft :lol:
gerold hat geschrieben: Die Datei ist im Encoding UTF-8 abgespeichert. Und das ist kein Unicodestring sondern ein Bytestring. Unicode verwendest du nur Python-intern.
Da möchte ich mich gar nicht groß auf Diskussionen einlassen da ich bei diesem Thema sowieso immer viel zu viel durcheinanderwürfel. Bitte sag mir doch nur jeamand das ich das nicht total falsch verstanden habe. Ich habe es bislang so verstanden:
Wenn ich einen Texteditor nehme und ihm sage: benutze zum speichern bitte das Encoding 'utf-8'. Dann geht er hin, nimmt die Zeichen die ich in meinem Text habe, nimmt sich die passende Unicodetabelle und setzt für jedes von mir eingegebene Zeichen die passenden Bytes in das File das ich abspeichern möchte.
Wenn ich die Datei später wieder mit der korrekten Darstellung anzeigen möchte weiss ich entweder was ich für ein encoding nehmen muss oder aber ich schreibe es ganz oben in einem Encoding das jeder lesen kann an den Anfang der Datei (in python halt # -*- coding: utf-8 -*-). Als letzte Möglichkeit kann ich dann noch versuchen zu raten welches Encoding benutzt wurde und einfach ausporbieren - wobei ich immer wieder lustige Zeichen bekommen werde

nochmal ein Danke für die schnelle und ausführliche Hilfestellung. So machts richtig Spass :)
Sebastian
Antworten