Encoding Probleme mit minidom

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7471
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Encoding Probleme mit minidom

Beitragvon Hyperion » Freitag 21. September 2007, 13:04

Hallo zusammen,

ich weiß, dass der Titel schlimmes ahnen lässt und das dieses Thema in unzähligen Threads behandelt wurde und alle Regulars hier sicherlich nerven wird, aber leider habe ich auch nach dem Studium von zig Tutorials und Dokus wohl einiges noch nicht abschließend kapiert.

Kurz etwas zum Problem: Ich bin dabei ein kleines CGI-Script zu schreiben, das auf meinem Uni-Webspace laufen soll. Auf der Maschine verrichtet ein Apache seinen Dienst und das ganze läuft auf einem RedHat System. Python liegt dort (nur) in Version 2.3 vor.

Nun habe ich dort leider massive Codierungsprobleme beim Auswerten und Speichern der Userdaten. Am Schluss soll es eine Ausgabe auf einer HTMl-Seite geben und die Daten sollen per minidom in ein XML-File geschrieben werden. So viel zum "eigentlichen" Problem.

So, ich habe nun mal versucht mich der Sache einfach per Shell zu nähern und einfach mal verschiedene Sachen auszuprobieren, vor allem Dinge aus dem umfangreichen Tutorial http://www.python-forum.de/viewtopic.php?p=30572#30572, welches hier gerne als Hilfe angegeben wird.

Im folgenden mal die Auszüge aus der Python-Shell auf dem Uni-Rechner.

Code: Alles auswählen

>>> s = "Österreich"
>>> print s
Österreich

Na das klappt ja :)

Code: Alles auswählen

>>> s.decode("ascii")
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)

Also bedeutet das, dass der Ursprungszeichensatz gar kein "ascii" war? Dies wäre eigentlich kein Problem, wenn ich nicht folgendes rausgefunden hätte:

Code: Alles auswählen

>>> sys.getdefaultencoding()
'ascii'

Beduetet das nicht, dass diese Python-Instanz ascii-Kodierung verwendet?
Aber wie kann ich dann überhaupt ein "Österreich" eintippen?

Ok, dann habe ich mal folgendes gemacht:

Code: Alles auswählen

>>> s.decode("utf-8")
u'\xd6sterreich'

Sieht nach Unicode aus, oder?

Code: Alles auswählen

>>> s.decode("utf-8").encode("utf-8")
'\xc3\x96sterreich'

Wieso wandelt er nun das "\xd6" also das "Ö" nicht wieder in ein "Ö"?
Und das geht auch nicht!

Code: Alles auswählen

>>> s.decode("utf-8").encode("ascii")
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
UnicodeEncodeError: 'ascii' codec can't encode character u'\xd6' in position 0: ordinal not in range(128)

Aber ascii soll doch angeblich der defaultencoding sein ... ich blicks einfach nicht (und ja, in ascii gibt es keine "ä","ö" usw ... daher bin ich noch verwirrter wie das alles zusammenhängt!)

Code: Alles auswählen

>>> sys.getfilesystemencoding()
'UTF-8'

Das besagt doch, dass die Parameter des OS in utf-8 übergeben werden, oder? Also sollten doch meine Texte aus dem CGI-Script und dem zugehörigen textarea als utf-8 übergeben werden, oder?

Ich habe also mal folgendes kleine Script geschrieben, um ein paar Sachen zu testen:

Code: Alles auswählen

import sys

print "default:",sys.getdefaultencoding()
print "filesystem:",sys.getfilesystemencoding()
print
print "Parameter:",sys.argv[1]

try:
   print "von utf-8",sys.argv[1].decode("utf-8")
except Exception, e:
   print e

try:
   print  "von ascii",sys.argv[1].decode("ascii")
except Exception, e:
   print e

try:
   print  "von iso-8859-15",sys.argv[1].decode("iso-8859-15")
except Exception, e:
   print e

Hier die Ausgabe: (lokal erhalte ich sogar dieselbe)

Code: Alles auswählen

as:> python parameter.py ä
default: ascii
filesystem: UTF-8

Parameter: ä
von utf-8 ä
von ascii 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)
von iso-8859-15 À

Wenn ich das richtig begreife bekommt also Python den Übergabeparameter tatsächlich als utf-8. Wieso aber meckert dann mein Script, wenn es "ä", "ö" usw. erhält?

Hier mal der Auszug von der Stelle, an der der fehler auftritt:
(doc ist das xml-Dokument per minidom erstellt)

Code: Alles auswählen

   try:
      tmp = doc.toxml()
      print tmp
      #f = codecs.open(file,"w","utf-8")
      #f.write(tmp)
      #f.close()
   except Exception, e:
      drawError("Fehler beim Speichern der aktuellen Sprüche",e)
      sys.exit(1)

(Die Kommentare sind nur "Bastel"-Sachen, die ich mal auskommentiert habe. Der Fehler liegt also def. am toxml() von minidom!

Code: Alles auswählen

'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)

Bekomme ich als Fehler, Eingabe war "ääööö"

Ich bin irgend wie mit meinem Latein am Ende!
Thomas W.
User
Beiträge: 17
Registriert: Sonntag 9. April 2006, 08:36
Wohnort: Halle (Saale)

Umlauten, Unicode und Encodings

Beitragvon Thomas W. » Freitag 21. September 2007, 13:15

Ich will mich erst noch mit Unicode und UTF beschäftigen und kann deshalb Deine Fragen nicht beantworten. Eine gute Übersicht habe ich aber schon mal unter [wiki]Von Umlauten, Unicode und Encodings[/wiki] gefunden. Vielleicht hilft sie Dir weiter, Unicode, UTF und Encodings zu verstehen. Ansonsten sie mal unter http://www.python-forum.de/topic-6539.html nach.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7471
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Beitragvon Hyperion » Freitag 21. September 2007, 13:19

Danke, der erste Link ist mir bekannt, ist quasi derselbe Beitrag aus dem Board hier ;)

Werd das zweite mal antesten ... wobei es bei mir ja keine Darstellungsprobleme gibt, sondern interne Fehler ...
BlackJack

Beitragvon BlackJack » Freitag 21. September 2007, 13:26

Ich weiss nicht ob man da überhaupt noch was sagen kann/soll. Du hast Unicode nicht verstanden und es gibt in der Tat genug Beiträge dazu.

Nur mal so um das erste Missverständnis auszuräumen:

Code: Alles auswählen

s = 'Österreich'


`s` enthält hier keine Buchstaben sondern irgendwelche Bytes die als Buchstaben interpretiert werden können. Einfach zu sagen `s` fängt mit einem 'Ö' an ist falsch, weil man das nicht weiss! Es kommt immer darauf an wie die Zeichenkette kodiert ist und ob das die Kodierung ist, von der man ausgeht.

Bei Dir sind das zum Beispiel zwei Bytes die das 'Ö' ausmachen, weil Deine Zeichenkette offenbar UTF-8 kodiert ist.

XML ist Unicode, also verwende dort am besten auch Unicode.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7471
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Beitragvon Hyperion » Freitag 21. September 2007, 13:37

BlackJack hat geschrieben:Ich weiss nicht ob man da überhaupt noch was sagen kann/soll. Du hast Unicode nicht verstanden und es gibt in der Tat genug Beiträge dazu.

Ja, aber die haben mir nicht geholfen ;)
Nur mal so um das erste Missverständnis auszuräumen:

Code: Alles auswählen

s = 'Österreich'


`s` enthält hier keine Buchstaben sondern irgendwelche Bytes die als Buchstaben interpretiert werden können. Einfach zu sagen `s` fängt mit einem 'Ö' an ist falsch, weil man das nicht weiss! Es kommt immer darauf an wie die Zeichenkette kodiert ist und ob das die Kodierung ist, von der man ausgeht.

Wo habe ich geschrieben, dass s mit "Ö" anfängt? Mir geht es ja grad darum, wie s codiert wird!
Bei Dir sind das zum Beispiel zwei Bytes die das 'Ö' ausmachen, weil Deine Zeichenkette offenbar UTF-8 kodiert ist.

Wie ich ja auch vermutet hatte ...
XML ist Unicode, also verwende dort am besten auch Unicode.

Ja genau das klappt ja leider nicht! Die Methode .toxml() wirft ja grad die Exception mit dem Codierungsfehler! Ist mir leider ein Rätsel, weil die Zeichenkette ja über das Webinterface in das Script gelangt und somit ja utf-8 sein sollte!
Benutzeravatar
Hyperion
Moderator
Beiträge: 7471
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Beitragvon Hyperion » Freitag 21. September 2007, 14:00

So, ich habe mal folgendes minimal Test-Script geschrieben, um zu sehen, ob ich den Fehler reproduzieren kann:

Code: Alles auswählen

#! /usr/bin/python
# -*- coding: utf-8 -*-
from xml.dom.minidom import getDOMImplementation
import sys

def main(args):
   impl = getDOMImplementation()
   doc = impl.createDocument(None, "test", impl.createDocumentType("noNamespaceSchemaLocation",None,None))
   root = doc.documentElement
   text = doc.createTextNode(args[1])
   root.appendChild(text)
   print doc.toprettyxml()

if __name__ == "__main__":
   main(sys.argv)

Wenn ich das nun auf dem Server aufrufe, bekomme ich folgendes korrektes Ergebnis:

Code: Alles auswählen

as:> ./mindom-example.py halloäöüö
<?xml version="1.0" ?>
<!DOCTYPE noNamespaceSchemaLocation>
<test>
        halloäöüö
</test>

Jetzt bin ich entgültig verwirrt! Wieso klappt das damit? Die einzige Schlussfolgerung, die ich im Moment ziehen kann ist folgende: Der Apache übergibt dem Script die Parameter eben nicht im "utf-8" ... aber wie kann das sein? Und vor allem, wie denn sonst?
BlackJack

Beitragvon BlackJack » Freitag 21. September 2007, 14:47

Hyperion hat geschrieben:
XML ist Unicode, also verwende dort am besten auch Unicode.

Ja genau das klappt ja leider nicht! Die Methode .toxml() wirft ja grad die Exception mit dem Codierungsfehler! Ist mir leider ein Rätsel, weil die Zeichenkette ja über das Webinterface in das Script gelangt und somit ja utf-8 sein sollte!


Ich sagte verwende Unicode, nicht UTF-8. Das ist nicht das gleiche!
Benutzeravatar
Hyperion
Moderator
Beiträge: 7471
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Beitragvon Hyperion » Freitag 21. September 2007, 14:52

So, ich habe das Test-Script mal so umgestellt, dass es einen Parameter per CGI bekommt und diesen als TextNode einträgt.

Rufe ich das Script dann per Browser mit Parameter auf, so kann er auch Umlaute korrekt darstellen! (genauer .toxml() meckert nicht rum!)

Genau diesen Codeschnipsel habe ich nun mal in mein eigentlichs Script an die Stelle des Speicherns gesetzt und den alten Code auskommentiert. Ergebnis: Es kommt wieder er coding Fehler!

Wie kann das nun sein? Fakt ist doch, dass beide Scripte an den imho entscheidenden Stellen exakt identischen Code haben und der Aufruf ebenfalls identisch ist. Wieso geht es bei dem einen, beim anderen kommt dieser scheiß codierungs Fehler?

Auf Wunsch kann ich den kompletten Code gerne posten, aber da der doch relativ lang ist, hoffe ich erst einmal auf einen dummen Bock meinerseits, der einfach zu erkennen ist.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7471
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Beitragvon Hyperion » Freitag 21. September 2007, 14:57

BlackJack hat geschrieben:Ich sagte verwende Unicode, nicht UTF-8. Das ist nicht das gleiche!

Ok, also muss ich an einer Stelle wohl einen .decode("utf-8") einfügen, um die vermeindliche utf-8 zeichenkette explizit in unicode zu wandeln, korrekt?
BlackJack

Beitragvon BlackJack » Freitag 21. September 2007, 15:47

Falls es UTF-8 ist, sollte das gehen. Ich bin jetzt zu faul in den RFCs zu wühlen, aber soweit ich das in Erinnerung habe antworten Browser mit der Kodierung in der die Seite bei ihnen ankam.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7471
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Beitragvon Hyperion » Freitag 21. September 2007, 15:56

BlackJack hat geschrieben:Falls es UTF-8 ist, sollte das gehen. Ich bin jetzt zu faul in den RFCs zu wühlen, aber soweit ich das in Erinnerung habe antworten Browser mit der Kodierung in der die Seite bei ihnen ankam.

Leider geht das ja genau nicht! Daher habe ich die Test-Scripte geschrieben, um das auszutesten.
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Freitag 21. September 2007, 20:09

Und warum kein Ö angezeigt wird, wenn dein "Österreich" in in Unicode enkodiert und dann in UTF-8 kodiert wird ist auch einfach zu erklären: ``repr()`` gibt bei Unicode-Strings immer "Sonderzeichen" als ``\x??``-Sequenzen aus, Wenn du einen Unicode-String direkt im Interpreter angibst, bekommst du die Ausgabe von ``repr()``. Du musst schon ``print`` verwenden.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
Hyperion
Moderator
Beiträge: 7471
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Beitragvon Hyperion » Samstag 22. September 2007, 11:56

Danke, das ist mal eine gute Erklärung :)

Und das andere Problem? Irgend eine Ahnung, wie ich den form-Parameter nun in unicode wandeln kann?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7471
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Beitragvon Hyperion » Sonntag 23. September 2007, 15:25

*push*
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Sonntag 23. September 2007, 17:21

Oh, sorry, habe deinen Post ganz übersehen,

Hyperion hat geschrieben:Und das andere Problem? Irgend eine Ahnung, wie ich den form-Parameter nun in unicode wandeln kann?

Form-Parameter?

Du kannst Bytestrings alle mit ``bytestringobjekt.encode('encoding_des_bytestrings')`` zu machen (wobei ``encode()`` natürlich einen Unicode-String zurückgibt und nicht den Bytestring ändert, versteht sich).
My god, it's full of CARs! | Leonidasvoice vs Modvoice

Wer ist online?

Mitglieder in diesem Forum: Sirius3