lxml.etree und Unicode-String-Verwirrung

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.
Antworten
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Hallo zusammen,

mal wieder eine Variante dieses "lästigen" Themas.

Mir ist aufgefallen, dass bei lxml das ".text"-Attribut der Element-Klasse(n) als Typen mal unicode und mal str hat.

Folgendes Beispiel soll das mal verdeutlichen:

Code: Alles auswählen

In [9]: foo = u"<root><bar>Hallöle</bar><bar>ohne special chars</bar></root>"

In [10]: root = etree.fromstring(foo)

In [11]: print type(root.getchildren()[0].text)
-------> print(type(root.getchildren()[0].text))
<type 'unicode'>

In [12]: print type(root.getchildren()[1].text)
-------> print(type(root.getchildren()[1].text))
<type 'str'>
Wie man sieht, gibt einem die property ".text" bei speziellen Chars (also solchen aus dem ASCII-Bereich) Objekte vom Typ str zurück, ansonten unicode.

In der Doku steht dazu folgendes:
lxml Doku (__Element) hat geschrieben: text
Text before the first subelement. This is either a string or the value None, if there was no text.
Das passt imho nicht zusammen, oder?

Nun meine Fragen: Kann man lxml dazu bewegen nur mit unicode zu arbeiten, oder wenn nicht, wie wäre dann die best-practise, wenn man Text-Elemente intern weiter verarbeiten will? (Dazu müßte man ja per if-else ne Abfrage nach dem Typen basteln?)
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Ich würde sagen du hast 2 Möglichkeiten: Mal die Entwickler fragen, was sie sich dabei gedacht haben, vllt ist das ja einfach ein fehlerhaftes Verhalten ;)

Oder du schreibst dir eine Funktion die das wrappt und zu `unicode` verändert, falls es keines ist.
BlackJack

Das ist Absicht, weil `str` einfach weniger Speicher verbraucht. Und der DocString ist auch nicht wirklich falsch, denn da steht "string" und nicht `str`. Allgemein als Zeichenketten kann man sowohl `str` als auch `unicode` bezeichnen.

Wo ist denn das konkrete Problem? `str` und `unicode` "mischen" führt ja eigentlich nur zu Problemen, wenn `str` etwas ausserhalb von ASCII enthält, weil bei impliziten Umwandlungen immer ASCII als Kodierung verwendet wird.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Letztendlich ist die Lösung einfach ein Aufruf von ``unicode()`` - wenn es vorher bereits Unicode ist, dann stört es nicht, wenn es ein ``str`` ist, dann wird es in ASCII sein und die Konversion in Unicode ist auch problemlos.
Aber vielleicht gibt es ja auch eine lxml-Option, um das zu konfigurieren.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

BlackJack hat geschrieben:Das ist Absicht, weil `str` einfach weniger Speicher verbraucht.
Hm ... wird nicht eigentlich immer "gepredigt", dass man intern möglichst mit Unicode arbeiten sollte? Wenn ich XML parse, dann will ich ja meist intern damit weiterarbeiten, weswegen ich es als praktisch empfunden hätte, wenn man Unicode bekommt. Aber mag auch sein, dass ich das hier zu sehr aus meiner Warte sehe und dabei andere Use-Cases übersehe.
BlackJack hat geschrieben: Und der DocString ist auch nicht wirklich falsch, denn da steht "string" und nicht `str`. Allgemein als Zeichenketten kann man sowohl `str` als auch `unicode` bezeichnen.
Stimmt! War ich zu voreilig mit meiner Kritik ;-)
BlackJack hat geschrieben: Wo ist denn das konkrete Problem? `str` und `unicode` "mischen" führt ja eigentlich nur zu Problemen, wenn `str` etwas ausserhalb von ASCII enthält, weil bei impliziten Umwandlungen immer ASCII als Kodierung verwendet wird.
Naja, da lag schon genau das Problem. Und daher wollte ich Unicode in meinem Programm haben. Ich habe halt nach ein paar Fehlversuchen gemerkt, dass das nicht konsistent zurückgeliefert wird.
Leonidas hat geschrieben: Letztendlich ist die Lösung einfach ein Aufruf von ``unicode()`` - wenn es vorher bereits Unicode ist, dann stört es nicht, wenn es ein ``str`` ist, dann wird es in ASCII sein und die Konversion in Unicode ist auch problemlos.
Jo, das ist ja wirklich einfach :-)
Wovon geht unicode() eigentlich aus, wenn man kein "encoding" angibt? Von ASCII oder dem coding-Cockie? (in diesem Falle spielt es ja keine Rolle, aber würde mich schon mal für die Zukunft interessieren)
Leonidas hat geschrieben: Aber vielleicht gibt es ja auch eine lxml-Option, um das zu konfigurieren.
Tja, ich habe lange und viel gesucht und nichts gefunden - vielleicht hat ja jemand anderes mehr Glück :-)
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Hyperion hat geschrieben:Wovon geht unicode() eigentlich aus, wenn man kein "encoding" angibt? Von ASCII oder dem coding-Cockie? (in diesem Falle spielt es ja keine Rolle, aber würde mich schon mal für die Zukunft interessieren)
ASCII in 2.x, sagt ja auch die Fehlermeldung ;) Es sei denn, es sind Literale, dann wird das Codingcookie genutzt.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

cofi hat geschrieben:Es sei denn, es sind Literale, dann wird das Codingcookie genutzt.
Dann wird aber nicht ``unicode()`` benutzt, von dem her.. :)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Das stimmt, aber ich wollte noch den Keks unterbringen, bevor das Krümelmonster vorbeikommt :)
BlackJack

@Hyperion: Intern nur mit Unicode arbeiten ist schon richtig, nur macht es eben bei `str`, die nur ASCII enthalten keine Probleme. Problematisch ist doch nur immer wenn Unicode und `str` mit Zeichen ausserhalb von ASCII in Berührung kommen. *Dann* kracht's. Bei Operationen mit `unicode` und `str`, seien das nun Vergleiche, ``+``, Zeichenkettenformatierung, wird automatisch immer der `str` in `unicode` umgewandelt. Und zwar mit ASCII als Kodierung. Wenn der also nur ASCII enthält -- kein Problem.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

BlackJack hat geschrieben:@Hyperion: Intern nur mit Unicode arbeiten ist schon richtig, nur macht es eben bei `str`, die nur ASCII enthalten keine Probleme. Problematisch ist doch nur immer wenn Unicode und `str` mit Zeichen ausserhalb von ASCII in Berührung kommen. *Dann* kracht's. Bei Operationen mit `unicode` und `str`, seien das nun Vergleiche, ``+``, Zeichenkettenformatierung, wird automatisch immer der `str` in `unicode` umgewandelt. Und zwar mit ASCII als Kodierung. Wenn der also nur ASCII enthält -- kein Problem.
Danke noch mal für die Erklärung. Ich stand vorhin ein wenig auf dem Schlauch und hatte einen Byte-String in meinem Script statt einem Unicode-String. Dabei ging es dann regelmäßig in die Hose ... dabei stieß ich dann eben auf diese Problematik. Ok, hätte ich also sonst gar nicht mitbekommen. Aber immerhin weiß ich jetzt um dieses Verhalten - und mit unicode() kann ich nun eben auch erreichen, dass ich in meiner späteren Ergebnis-Struktur nur noch Unicode habe, das ich dann sauber wandeln kann.
Antworten