XML Handling in Python

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
template
User
Beiträge: 29
Registriert: Mittwoch 21. November 2007, 09:44

Hallo,

habe gerade ein bischen mit dem xml.minidom Interface herumgespielt. Das DOM Interface kommt mir aber doch sehr Umständlich vor, vor allem für Python verhältnisse;) Hier ein Sample um die Struktur <root attrib="value"><foo>hello, world!</foo></root> zu erstellen:

Code: Alles auswählen

root = dom.createElement("root")
root.setAttribute("attrib", "value")
x = dom.createElement("foo")
txt = dom.createTextNode("hello, world!")
x.appendChild(txt)
root.appendChild(x)
zum vergleich habe ich hier mal einen C++ Code notiert, der eine XML Klasse von mir verwendet, und das selbe tut:

Code: Alles auswählen

doc = new XmlDoc();
doc.QuerySetBaseNode("/root[force]");
doc.QuerySetValue("foo[force]", "hello, world!");
doc.QuerySetAttribute(".", "attrib", "value");
Das soll jetzt nicht heisen, das ich genau die selbe Funktionalität unter Python erwartet habe, aber ich habe mir irgendwie erhofft das es ein leichter zu benutzendes Interface gibt.

Gibt es irgendwelche alternativen Wege um eine XML Struktur zu erstellen z.B. mithilfe von XPath oder ähnlichem?

Vielen dank im voraus
template
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

template hat geschrieben:Gibt es irgendwelche alternativen Wege um eine XML Struktur zu erstellen z.B. mithilfe von XPath oder ähnlichem?
Ja, ElementTree und lxml.

Minidom implementiert nun mal das aus Java bekannte DOM-Interface, da kann man ja nicht erwarten, dass es simpel zu bedienen ist.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
template
User
Beiträge: 29
Registriert: Mittwoch 21. November 2007, 09:44

Danke für die schnelle Antwort.

Ja, das klingt durchaus einleuchtend. Ich habe zuerst auch mit dem ElementTree gearbeitet, bin aber dann im Endeffekt daran gescheitert, das die tostring Funktion keine formatierte Ausgabe liefert:(
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

template hat geschrieben:bin aber dann im Endeffekt daran gescheitert, das die tostring Funktion keine formatierte Ausgabe liefert:(
Hallo template!

Meinst du mit formatiert, eingerückt?

Code: Alles auswählen

try:
    from elementtree import ElementTree as et
except ImportError:
    from xml.etree import ElementTree as et


def indent(elem, level=0):
    i = "\n" + level*"  "
    if len(elem):
        if not elem.text or not elem.text.strip():
            elem.text = i + "  "
        for child in elem:
            indent(child, level+1)
        if not child.tail or not child.tail.strip():
            child.tail = i
        if not elem.tail or not elem.tail.strip():
            elem.tail = i
    else:
        if level and (not elem.tail or not elem.tail.strip()):
            elem.tail = i
    return elem


#...

indent(root)
xml = (
    '<?xml version="1.0" encoding="utf-8"?>\n' +
    et.tostring(root, "utf-8")
)
Siehe: http://effbot.org/zone/element-lib.htm#prettyprint

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

Ich hab auch erst darüber geschimpft das es nötig ist einen solchen prettyprint-hack dort einzubauen. Aber es macht doch Sinn und mit kleinen Änderungen kann man sich auch indiviuell benötigte Prints bauen die zB jedes Value eines Knotens in einer eigenen Zeile darstellt. (Gut zum Diffen von Änderungen)
template
User
Beiträge: 29
Registriert: Mittwoch 21. November 2007, 09:44

Danke für das Codeschnippsel. Ich bin jetzt aber doch auch das minidom interface umgestiegen. Da baue ich mir jetzt noch ne abgeleitete Klasse drüber, die noch ein bischen bessere High-Level Funktionalität drüber stellt und dann geht das schon. Ich hatte nur irgendwie gehofft, den Schritt könnte ich mir komplett sparen, aber es versteht ja auch jeder etwas anderes unter eine Möglichst schnell und leicht zu benutzenden API;)
poker
User
Beiträge: 146
Registriert: Donnerstag 20. September 2007, 21:44

@gerold
Huch,

Code: Alles auswählen

    else:
        if level and (not elem.tail or not elem.tail.strip()):
            elem.tail = i
warum nicht gleich so:

Code: Alles auswählen

    elif level and (not elem.tail or not elem.tail.strip()):
            elem.tail = i
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

poker hat geschrieben:warum nicht gleich so:
Hallo poker!

Weil ich mir den Code nie ganz durchgelesen habe: http://effbot.org/zone/element-lib.htm#prettyprint

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
poker
User
Beiträge: 146
Registriert: Donnerstag 20. September 2007, 21:44

Leonidas hat geschrieben: Ja, ElementTree und lxml.
Wobei IMO `lxml` der Vorrang gegeben werden sollte, wenn die Aufgaben "groß" sind. Ich finde `ElementTree` ähnlich wie `BeautifulSoup` "Trash" bzw. für kurze dirty Jobs zu gebrauchen...Es fehlen einfach Validierungsmöglichkeiten...

lxml bietet da viel mehr:
Validierung in `DTD`, `RelaxNG` (Ich liebe RelaxNG :D) und `XMLSchema`.
Dan das IMO unverzichtbare XPath and XSLT und eine `ElementTree` kompatible API, ...

Ich frage mich, warum man `ElementTree` nicht mal langsam durch `lxml` ersetzt. Ernsthaft!! Es ist quasi das verbesserte `ElementTree` mit viel mehr...

Aber ich merke mal wider, ich bin total OT. Hauptsache par buzzwords noch mal schnell losgeworden :D -- Ne ernsthaft, OP try `lxml`...
poker
User
Beiträge: 146
Registriert: Donnerstag 20. September 2007, 21:44

gerold hat geschrieben:
poker hat geschrieben:warum nicht gleich so:
Hallo poker!

Weil ich mir den Code nie ganz durchgelesen habe: http://effbot.org/zone/element-lib.htm#prettyprint

mfg
Gerold
:-)
Huch, das sowas effbot passiert...
Benutzeravatar
BlackVivi
User
Beiträge: 762
Registriert: Samstag 9. Dezember 2006, 14:29
Kontaktdaten:

Öhm... Findest du nicht, dass du'n bissel übertreibst? Ich find's so mit dem else eigentlich sogar übersichtlicher oO' Is jetzt nicht so, als hätte er den PEP8 superpervers gebrochen und man ihm'ne Email schicken muss oO..

Hab schon recht viele Dokumentationen von Bibliotheken gelesen, die sogar * importe benutzt haben. Außerdem find' ich BeautifulSoup überhapt nicht trashig o_o Mit ETree hab ich schon recht viel gearbeitet und gemerkt, dass's manchmal ein bisschen... tückisch wird. Unsauber aussieht bei großen Strukturen. Aber kein Weltuntergang... Aber BeautifulSoup? Wie auch BlackJack würd ich es sogar begrüßen, wenn's in'r Stdlib wär!
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

poker hat geschrieben:@gerold
Huch,

Code: Alles auswählen

    else:
        if level and (not elem.tail or not elem.tail.strip()):
            elem.tail = i
warum nicht gleich so:

Code: Alles auswählen

    elif level and (not elem.tail or not elem.tail.strip()):
            elem.tail = i
Da geht noch was! :)

Code: Alles auswählen

    elif level and not (elem.tail and elem.tail.strip()):
            elem.tail = i
poker
User
Beiträge: 146
Registriert: Donnerstag 20. September 2007, 21:44

BlackVivi hat geschrieben:Öhm... Findest du nicht, dass du'n bissel übertreibst? Ich find's so mit dem else eigentlich sogar übersichtlicher oO'
Ne finde ich nicht. Schaum mal: Der `if len(elem):`-Block ist total sinnvoll, da darin, plump gesagt, viel passiert, wohingegen beim `else:`-Block außer einer if abfrage nichts passiert. Eine `else` verzeweigung in der *nur* ein `if` ist, kann man gleich als `else if` verbinden. Es ist IMO sauberer.

Ist so ähnlich wie das ein ``else: pass`` total überflüssig ist. Ist so ähnlich wie das man `if eggs` und nicht `if eggs is True` oder gar `if eggs == True` schreibt.

Das hat was mit der Einstellung zu tun...Bleibt aber jedem selbst überlassen (Und darauf liegt die Betonung)...ich dachte nur, da hier ein par Klugscheißer (So genante Regulars) rumlaufen die jeden Furz kommentieren, probiere ich mal und schau wie lang es dauert bis... ;)

Wie dem auch sei...heißt aber nicht das dass was ich oben geschrieben habe falsch wäre! Ist absolut richtig und wird auch so gelehrt.
Oder kriegt man neuerdings im IT-Unterricht keine Abzüge für sowas?

Code: Alles auswählen

if blubb:
    ...
else:
    if bbulb:
        ...
BlackVivi hat geschrieben: Is jetzt nicht so, als hätte er den PEP8 superpervers gebrochen und man ihm'ne Email schicken muss oO..
Das hat nichts mit PEP8 zu tun, ausserdem kenst du meine Einstellung bezüglich PEP8 und der Allgemeinen Dogmatik hier ;) Du kannst das obere auch so ausfassen, als etwas das zwar richtig ist aber gleichzeitig die Regulars ein wenig veräppelt ;) U See?

BlackVivi hat geschrieben: Hab schon recht viele Dokumentationen von Bibliotheken gelesen, die sogar * importe benutzt haben.
Solche Libs gleich kicken. Auch Libs wo sich keine mühe für doku gegeben wird. Wenns schon bei sowas scheitert, wie viel vertrauen soll man dann in die Qualität des restlichen codes haben!?
BlackVivi hat geschrieben: Außerdem find' ich BeautifulSoup überhapt nicht trashig o_o]
Es ist Geschmacksachen und ich habe auch "IMO" geschrieben. `BeautifulSoup` ist dafür zu gebrauchen für das es auch ursprünglich gedacht war: Parsen und reparieren von Kaputten HTML Seiten (Nicht shclißende Tags, ...). Daher auch der Name Beautiful Soup, halt wunderbare Seife, das eine Anspielung an die soup parsern der Browser sein soll die damit Kapute Seiten im quirks-mode parsen.

Alles wo es dann darum geht wirklich viele und dicke Seiten zu *verarbeiten* ist BeautifulSoup total speicher fressend (hat Probleme mit Zirkulären Referenzen die es nicht durchbrechen kann, etc...Da kannte jamand das `weakref` modul nicht), *sehr langsam*, ...

Ehrlich, wenn ich weiß das $SITE eine feste sich nicht ändernd (zumindest für die nächsten 3 Jahre) Struktur aufweißt, dann benutze ich regexes. Und das meine ich ehrlich. Erstens wird IMO der Code übersichtlicher (Ja, obwohl regexes vorhanden sind ;), das parsen geht viel schneller, etc. Für komplexere Sachen, verwende ich halt die Standard XML-Parser...

Und wenn es schnell gehen soll und auf ein wegwerfscript hinausläuft dan BeautifulSoup oder lieber gleich Ruby.
BlackVivi hat geschrieben: Mit ETree hab ich schon recht viel gearbeitet und gemerkt, dass's manchmal ein bisschen... tückisch wird. Unsauber aussieht bei großen Strukturen. Aber kein Weltuntergang...
Die API von ElementTree ist OK und bis auf das von dir angesprochene auch nicht das Problem (Arbeite mal mit DOM, da kriegst du das schreien :D). Was mich stört ist, das es sehr beschränkt ist. Keinerlei Validierungsmöglichkeiten und so weiter (Siehe oberen Post von mir).

Ehrlich, wenn ich eine Software entwickle die ein XML-Dateiformat verwendet das ich oder andere spezifizieren müssen, dann erwarte ich das mindestens die Möglichkeit gegeben wird das ganze mir RelaxNG zu Formulieren, dass dann als Validierung gilt. DTD kommt für mich überhaupt nicht in frage, und selbst das bietet ElementTree nicht. -- Alles andere ist für mich nur gehacke und nicht Professionell (Ja, selbst die Validierung mit Python zu schreiben!! Wozu gibt es eben DTD, RelaxNG...)

`lxml` ist halt für mich ein Komplettpaket mit allem wichtigen was ich für XML brauch plus der Möglichkeit trotzdem die Vorzüge der ElementTree API zu nutzen, da komplett unterstütz mit erweiterungen. Außerdem ist `lxml` komplett in C (Python C-API, also ne Extension) und Python geschrieben und ein Wrapper um
`libxml2` and `libxslt` das nicht ganz unbekannt und gut ist. Dadurch ist es extrem schnell und schlägt ElementTree und auch (cElementTree). Versteh mich nicht falsch, effbot hat mit ElementTree wie auch mit SRE, ... Super dinger geschrieben, aber IMO ist es mittlerweile obsolete und sollte durch `lxml` ersetzt werden, da es neben der ElementTree-API und andere, auch wichtige Sachen beinhaltet die für "Professionelles" Arbeiten mit XML IMO notwendig sind.
BlackVivi hat geschrieben: Aber BeautifulSoup? Wie auch BlackJack würd ich es sogar begrüßen, wenn's in'r Stdlib wär!
Da spricht auch nichts dagegen, da es auf dem Gebiet für das es gedacht ist auch IMO für Python nichts besseres gibt (Falls einer einen besseren soup parser kennt, dann bitte Link posten). Ich benutzte ja BeautifulSoup wie angesprochen selber.
poker
User
Beiträge: 146
Registriert: Donnerstag 20. September 2007, 21:44

Y0Gi hat geschrieben: Da geht noch was! :)

Code: Alles auswählen

    elif level and not (elem.tail and elem.tail.strip()):
            elem.tail = i
Jepp! :)
BlackJack

Stefan Behnel macht in der englischsprachigen Python-Newsgroup gerne "Werbung" für lxml.html als Ersatz für `BeautifulSoup`.
poker
User
Beiträge: 146
Registriert: Donnerstag 20. September 2007, 21:44

BlackJack hat geschrieben:Stefan Behnel macht in der englischsprachigen Python-Newsgroup gerne "Werbung" für lxml.html als Ersatz für `BeautifulSoup`.
Hmm, naja, hab bisher [http://codespeak.net/lxml/dev/parsing.html#parsing-html etree.HTMLParser] für html genutzt, aber dann nur valides html.

Hast du lxml.html schon mal angetestet? Hab mir zwar die API vor mal grob durchgelesen (länger her) aber nichts wirklich getestet? Kann es mit der usability von `BeautifulSoup` mithalten?
Antworten