Ich versuche eine kleine Bibliothek zu erstellen, die das Lesen und Schreiben von kvtml Vokabeldateien ermöglicht.
Das kvtml Format ist ein Dateiformat, welches große Ähnlichkeiten mit XML Dateien hat. Das Auslesen und Schreiben sollte deshalb eigentlich problemlos mit der Standartbibliothek xml.etree.ElementTree möglich sein.
Ich bin allerdings auf zwei Probleme gestoßen, die ich trotz durcharbeiten der Referenz zu xml.etree.ElementTree nicht lösen konnte.
1) Strings mit Umlauten werden beim Auslesen automatisch in Unicodes umgewandelt; Wie kann ich die wieder in Utf-8 Strings umwandeln?
2) Wie kann ich die ersten beiden Zeilen der kvtml erstellen, also die Angaben über die xml version und encoding sowie den Doctype.
Ich bin mir mittlerweile ziemlich sicher das es nicht mit der Bibliothek xml.etree.ElementTree geht, aber selbst bei lxml habe ich nichts gefunden.
Mein bisheriger Code sieht so aus:
http://www.python-forum.de/pastebin.php?mode=view&s=4
Eine kvtml Vokabeldatei hat das folgende Format:
http://www.python-forum.de/pastebin.php?mode=view&s=5
PS: Die beiden Dateien die ich hochgeladen habe stehen unter der GPL.
Lesen und Schreiben von kvtml Vokabeldateien
-
- User
- Beiträge: 996
- Registriert: Mittwoch 9. Januar 2008, 13:48
Ubuntuxer hat geschrieben:Wie kann ich die wieder in Utf-8 Strings umwandeln?
Code: Alles auswählen
unicode_string.encode(encoding)
Das Erstere sollte eigentlich automatisch dazukommen. Zweiteres musst du wohl von Hand hinzufügen.xml version und encoding sowie den Doctype.
Ich empfehle dir auf jeden Fall lxml, weil das Hunderte Male schneller und schlanker ist.
@Ubuntuxer: Warum willst Du die Unicode-Objekte überhaupt als `str` haben? Wenn man mit Zeichen arbeiten will, ist `unicode` doch eigentlich genau das, was man eigentlich möchte!?
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Das ist xmlUbuntuxer hat geschrieben: Das kvtml Format ist ein Dateiformat, welches große Ähnlichkeiten mit XML Dateien hat.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
Das Problem ist, dass die HTML Ersatzzeichen für die Umlaute nicht wieder in Umlaute umgewandelt werden.Dauerbaustelle hat geschrieben:Code: Alles auswählen
unicode_string.encode(encoding)
u'T\xfcr'.encode('utf-8')
'T\xc3\xbcr'
Der KDE Vokabeltrainer Parley kann mit diesen Zeichen nicht umgehen, sodass nur die Sprache ohne Umlaute korrekt aus meiner erzeugten Datei eingelesen wird.
@Blackjack: Parley kann auch mit Unicodes nicht umgehen.
Und wie füge ich den Doctype per Hand hinzu???Das Erstere sollte eigentlich automatisch dazukommen. Zweiteres musst du wohl von Hand hinzufügen.xml version und encoding sowie den Doctype.
Wenn ich eine Datei einlese und danach neu schreibe sieht sie wie folgt aus:
http://www.python-forum.de/pastebin.php ... &mode=view
Ich empfehle dir auf jeden Fall lxml, weil das Hunderte Male schneller und schlanker ist.[/quote]
Ich meine xml.etree.cElementTree sei noch schneller als lxml, aber das ist mir eigentlich total egal. Hauptsache es funktioniert überhaupt!
@Ubuntuxer: Dann kann Parley nicht mit XML umgehen, was ich jetzt nicht so recht glauben mag, denn dann wäre das Programm für die Tonne.
@Ubuntuxer: Das würde insbesondere auch bedeuten das Parley nicht mit der Datei klarkommt, die Du da gezeigt hast, denn da sehe ich in Zeile 14 bei "Niederländisch" ziemlich deutlich ein 'ä'.
Ich habe da eher den Verdacht das Du etwas falsch machst. XML (das DOM) ist mit Unicode definiert, das kennt kein UTF-8. Die Zeichenketten mit Umlauten, welche Du als `unicode` bekommst, musst Du auch wieder als `unicode` in XML-Element-Objekte reinstecken! *Nicht* als UTF-8 kodierte `str`-Objekte -- da kommt Murks bei raus. Das ist einer der Gründe warum ich gefragt habe, warum Du die überhaupt kodieren willst.
Ich habe da eher den Verdacht das Du etwas falsch machst. XML (das DOM) ist mit Unicode definiert, das kennt kein UTF-8. Die Zeichenketten mit Umlauten, welche Du als `unicode` bekommst, musst Du auch wieder als `unicode` in XML-Element-Objekte reinstecken! *Nicht* als UTF-8 kodierte `str`-Objekte -- da kommt Murks bei raus. Das ist einer der Gründe warum ich gefragt habe, warum Du die überhaupt kodieren willst.
-
- User
- Beiträge: 996
- Registriert: Mittwoch 9. Januar 2008, 13:48
Ubuntuxer, siehe folgende Grafiken (weniger ist schneller ist besser):
Parsing
Serialization
(Quelle)
Parsing
Serialization
(Quelle)
@Dauerbaustelle: Ich zweifle mal die Relevanz an, weil es da ja wohl um potentiell kaputtes HTML geht und mir zumindest jetzt nicht klar ist, wieviel zusätzlichen Aufwand das jeweils macht das vorzuverarbeiten oder irgendwie anders beim Parsen zu berücksichtigen.
Kann ja zum Beispiel sein dass die beim reinen Parsen vom XML alle gleich schnell sind, sich aber in der "Korrekturphase" vorher unterschiedlich lange aufhalten.
Kann ja zum Beispiel sein dass die beim reinen Parsen vom XML alle gleich schnell sind, sich aber in der "Korrekturphase" vorher unterschiedlich lange aufhalten.
-
- User
- Beiträge: 996
- Registriert: Mittwoch 9. Januar 2008, 13:48
lxml hat ein eingebautes html-Modul, das das Parsen von kaputten HTML ziemlich effizient managed.
@Dauerbaustelle: Das untermauert, dass die Zahlen hier wertlos sind, weil der Unterschied zu einem relevanten Anteil im HTML-Teil liegen könnte. Um HTML geht es hier aber gar nicht.
Ich versuche einfach mal noch genauer zu beschreiben wo mein Problem liegt:BlackJack hat geschrieben:@Ubuntuxer: Das würde insbesondere auch bedeuten das Parley nicht mit der Datei klarkommt, die Du da gezeigt hast, denn da sehe ich in Zeile 14 bei "Niederländisch" ziemlich deutlich ein 'ä'.
Ich habe da eher den Verdacht das Du etwas falsch machst. XML (das DOM) ist mit Unicode definiert, das kennt kein UTF-8. Die Zeichenketten mit Umlauten, welche Du als `unicode` bekommst, musst Du auch wieder als `unicode` in XML-Element-Objekte reinstecken! *Nicht* als UTF-8 kodierte `str`-Objekte -- da kommt Murks bei raus. Das ist einer der Gründe warum ich gefragt habe, warum Du die überhaupt kodieren willst.
Ich parse zunächst die Orginal kvtml Datei von Parley und dabei z.B. das Wort "Niederländisch"
Die Bibliothek xml.etree.cElementTree wandelt seltsamerweise Wörter mit Umlauten in einen Unicode um, während Wörter ohne Umlaut normale Strings bleiben.
Dies bedeutet das Wort Niederländisch wird zu u'Niederl\xe4ndisch'.
Ich könnte das eingelesene Wort direkt in einen String umwandeln.
u'Niederl\xe4ndisch'.encode('utf-8') => 'Niederl\xc3\xa4ndisch'
Nun möchte ich die eingelesen Informationen wieder in eine neue kvtml Datei schreiben.
Code: Alles auswählen
text = ETree.SubElement(entry, "text")
text.text = u'Niederl\xe4ndisch'
Code: Alles auswählen
text = ETree.SubElement(entry, "text")
text.text = u'Niederl\xe4ndisch'.encode('utf-8')
Beides kann Parley nicht lesen.
Ich vermute einfach mal, dass xml.etree.cElementTree die Information braucht, wie es die zugewiesen Unicodes encoden soll. In der Orginaldatei steht ja auch: <?xml version="1.0" encoding="UTF-8"?>
Ohne die beiden Zeilen ersten Zeilen der Orginaldatei kann Parley meine erstellte Datei überhaupt nicht lesen.
Code: Alles auswählen
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE kvtml PUBLIC "kvtml2.dtd" "http://edu.kde.org/kvtml/kvtml2.dtd">
-
- User
- Beiträge: 996
- Registriert: Mittwoch 9. Januar 2008, 13:48
Du hast aber was davon erzählt o_OBlackJack hat geschrieben:Um HTML geht es hier aber gar nicht.
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Also mit lxml kein Problem:
(Bei mir ist in der Shell wohl latin-1 als default encoding eingestellt. Muss ich mal nachprüfen... ist ja vollkommen ätzend!)
Aber wie Du siehst kümmert sich lxml auch um Header-Infos. Kann mir aber nicht vorstellen, dass die ElementTree-API aus der Standard-Lib das nicht tut.
Code: Alles auswählen
In [17]: from lxml import etree
In [18]: with open("kvtml.xml", "r") as infile:
tree = etree.parse(infile)
....:
....:
In [20]: tree
Out[20]: <lxml.etree._ElementTree object at 0xb75adecc>
In [21]: tree.docinfo
Out[21]: <lxml.etree.DocInfo object at 0xb72eea34>
In [22]: tree.docinfo.doctype
Out[22]: u'<!DOCTYPE kvtml PUBLIC "kvtml2.dtd" "http://edu.kde.org/kvtml/kvtml2.dtd">'
In [23]: tree.docinfo
tree.docinfo
In [23]: tree.docinfo.
tree.docinfo.URL tree.docinfo.__reduce__ tree.docinfo.externalDTD
tree.docinfo.__class__ tree.docinfo.__reduce_ex__ tree.docinfo.internalDTD
tree.docinfo.__delattr__ tree.docinfo.__repr__ tree.docinfo.public_id
tree.docinfo.__doc__ tree.docinfo.__setattr__ tree.docinfo.root_name
tree.docinfo.__format__ tree.docinfo.__sizeof__ tree.docinfo.standalone
tree.docinfo.__getattribute__ tree.docinfo.__str__ tree.docinfo.system_url
tree.docinfo.__hash__ tree.docinfo.__subclasshook__ tree.docinfo.xml_version
tree.docinfo.__init__ tree.docinfo.doctype
tree.docinfo.__new__ tree.docinfo.encoding
In [23]: text = etree.Element("text")
In [24]: text.text = u"Niederländisch"
In [25]: text.text
Out[25]: u'Niederl\xc3\xa4ndisch'
In [26]: print text.text.encode("latin-1")
-------> print(text.text.encode("latin-1"))
Niederländisch
Aber wie Du siehst kümmert sich lxml auch um Header-Infos. Kann mir aber nicht vorstellen, dass die ElementTree-API aus der Standard-Lib das nicht tut.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
@Ubuntuxer: Das Zeichenketten mit Umlauten als `unicode`-Objekte von den diversen XML-Bibliotheken geliefert werden ist nicht seltsam sondern das normale Verhalten. Seltsam könnte man eher das Verhalten bei Zeichenketten nennen, die nur ASCII-Zeichen enthalten. Das wird so gemacht um Speicher zu sparen und weil man ASCII-Zeichenketten problemlos mit Unicode-Objekten "mischen" kann. Denn die können im Bedarfsfall ohne Fehler automatisch in Unicode-Objekte umegewandelt werden.
Du machst irgendwo etwas fundamental falsch, denn die gezeigten Quelltextschnippsel können nicht zu dem behaupteten Ergebnis führen.
Zeig mal bitte ein minimales Beispiel wie Du da ``<text>u'Niederl\xe4ndisch'</text>`` herausbekommen haben willst ohne irgendwann mal `repr()` die Daten anzuwenden.
@Dauerbaustelle: Ich habe nichts von HTML erzählt. Schon gar nichts was HTML-Parser hier irgendwie ins Spiel gebracht hätte.
Du machst irgendwo etwas fundamental falsch, denn die gezeigten Quelltextschnippsel können nicht zu dem behaupteten Ergebnis führen.
Code: Alles auswählen
In [571]: import xml.etree.cElementTree as ETree
In [572]: text = ETree.Element('text')
In [573]: text.text = u'Niederl\xe4ndisch'
In [574]: ETree.tostring(text)
Out[574]: '<text>Niederländisch</text>'
@Dauerbaustelle: Ich habe nichts von HTML erzählt. Schon gar nichts was HTML-Parser hier irgendwie ins Spiel gebracht hätte.
Uups, entschuldige ich hab da irgendetwas durcheinandergebracht.
Also es sieht bei mir so aus:
Orginal:
<name>Niederländisch</name>
Bei u'Niederl\xe4ndisch':
<name>Niederländisch</name>
Bei 'Niederl\xc3\xa4ndisch': (u'Niederl\xe4ndisch'.encode('utf-8'))
<name>Niederländisch</name>
Also es sieht bei mir so aus:
Orginal:
<name>Niederländisch</name>
Bei u'Niederl\xe4ndisch':
<name>Niederländisch</name>
Bei 'Niederl\xc3\xa4ndisch': (u'Niederl\xe4ndisch'.encode('utf-8'))
<name>Niederländisch</name>
@Ubuntuxer: Und wo liegt jetzt das Problem? ``<name>Niederländisch</name>`` ist gültiges XML das genau das gewünschte darstellt.
Ich habe gerade gemerkt, dass das tatsächlich ohne Probleme funktioniert.BlackJack hat geschrieben:@Ubuntuxer: Und wo liegt jetzt das Problem? ``<name>Niederländisch</name>`` ist gültiges XML das genau das gewünschte darstellt.
Parley konnte meine erstellte Datei aus einem anderen Grund nicht lesen. Anscheinend werden die Dateien von Parley irgendwie gecacht, sodass wenn ich die erstellte Datei ohne die beiden ersten Zeilen öffne und danach die Zeilen einfüge und noch einmal die Datei mit Parley öffne nur eine Sprache angezeigt wird. Ich dachte die ganze Zeit dies läge an den Unicodes, da die deutschen Wörter in Parley nicht angezeigt wurden.
Damit hat sich das Unicode Problem erledigt. Danke für deine Geduld Blackjack.
Hat einer noch eine Idee wie ich das Problem mit den ersten beiden Zeilen lösen kann?
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Hast Du meinen Post überlesen?Ubuntuxer hat geschrieben: Hat einer noch eine Idee wie ich das Problem mit den ersten beiden Zeilen lösen kann?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
Ich möchte den Doctype nicht auslesen, sondern in eine neue kvtml Datei reinschreiben. Mit lxml kann man zumindestens den Doctype auslesen, aber ich habe mir auch die lxml Referenz angeschaut und keine Erklärung gefunden wie man den Doctype in eine neue xml schreiben kann.Hyperion hat geschrieben:Hast Du meinen Post überlesen?Ubuntuxer hat geschrieben: Hat einer noch eine Idee wie ich das Problem mit den ersten beiden Zeilen lösen kann?
Code: Alles auswählen
from lxml import etree
root = etree.Element("kvtml")
root.set("version", "2.0")
tree = etree.ElementTree(root)
tree.docinfo.doctype = u'<!DOCTYPE kvtml PUBLIC "kvtml2.dtd" "http://edu.kde.org/kvtml/kvtml2.dtd">'