Python XML in einer Schleife generieren

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.
JustinJ
User
Beiträge: 14
Registriert: Sonntag 15. Januar 2012, 15:59

Hallo Ihr,


ich komme leider bei einer Aufgabe nicht mehr weiter. und zwar soll ich Elemente aus einer Liste auslesen und in eine andere Liste reinstellen. Dabei hab ich allerdings Probleme mit der for-Schleife. Es wäre nett, wenn mir dort jemand weiterhelfen könnte :). Ich möchte auch keine vollständige Lösung, sondern nur eine HIlfestellung was ich daran verbessern könnte bzw. anders machen könnte.

Code: Alles auswählen

import xml.etree.ElementTree as xmltree

tree = xmltree.parse("xmlprogrammliste.xml")
doc = tree.getroot()

xpos = ""
ypos = ""

resx = ""
resy = ""

lastuser = ""
lastusage = ""
serialcode = ""

date = []
data = []
user = []

get_picture_format = []
get_picture_base64 = []
picture_name = []

def read_configuration():
    configuration = doc.find("configuration")
    
    position = configuration.find("position")
    xpos = position.find("xpos").text
    ypos = position.find("ypos").text

    resolution = configuration.find("resolution")
    resx = resolution.find("resx").text
    resx = resolution.find("resy").text

    lastuser = configuration.find("lastuser").text
    lastusage = configuration.find("lastusage").text

    serialcode = configuration.find("serialcode").text

def read_history():
    history = doc.find("history")
    for function in history.getchildren():
        date.append(function.find("date").text)
        data.append(function.find("data").text)

        picture = function.find("picture")
        picture_base64 = picture.find("base64")

        get_picture_format.append(picture_base64.get("format"))
        get_picture_base64.append(picture_base64.text)
        picture_name.append(picture.find("name").text)

        user.append(function.find("user").text)

def write_element():
    read_configuration()
    read_history()

    writetree = xmltree.Element('dgraphconfig')


    configuration = xmltree.SubElement(writetree, 'configuration')

    position = xmltree.SubElement(configuration, 'position')
    xpos_tree = xmltree.SubElement(position, 'xpos')
    xpos_tree.text = xpos
    ypos_tree = xmltree.SubElement(position, 'ypos')
    ypos_tree.text = ypos

    resolution = xmltree.SubElement(configuration, 'resolution')
    resx_tree = xmltree.SubElement(resolution, 'resx')
    resx_tree.text = resx
    resy_tree = xmltree.SubElement(resolution, 'resy')
    resy_tree.text = resy

    lastuser_tree = xmltree.SubElement(configuration, 'lastuser')
    lastuser_tree.text = lastuser

    lastusage_tree = xmltree.SubElement(configuration, 'lastusage')
    lastusage_tree.text = lastusage

    serialcode_tree = xmltree.SubElement(configuration, 'serialcode')
    serialcode_tree.text = serialcode


    history = xmltree.SubElement(writetree, 'history')

    function = []
    date_tree = []
    data_tree = []
    picture = []
    pic_name = []
    pic_base64 = []
    user_tree = []
    for i in range(0, len(user) - 1):
        function.append(xmltree.SubElement(history, 'function'))
        date_tree.append(xmltree.SubElement(function[i], 'date'))
        date_tree[i].text = date[i]

        data_tree.append(xmltree.SubElement(function[i], 'data'))
        data_tree[i].text = data[i]

        picture.append(xmltree.SubElement(function[i], 'picture'))
        pic_name.append(xmltree.SubElement(picture[i], 'name'))
        pic_name[i].text = picture_name
        pic_base64.append(xmltree.SubElement(picture[i], 'base64'))
        pic_base64[i].set('format', get_picture_format[i])
        pic_base64[i].text = get_picture_base64[i]

        user_tree.append(xmltree.SubElement(function[i], 'user'))
        user_tree[i].text = user[i]
    tree = xmltree.ElementTree(writetree)
    tree.write("xmlbeispiel.xml")

#read_history()
write_element()
als fehlermeldung kommt:
Traceback (most recent call last):
File "/home/justin/Dokumente/xml-parser_readandwrite.py", line 116, in <module>
write_element()
File "/home/justin/Dokumente/xml-parser_readandwrite.py", line 113, in write_element
tree.write("xmlbeispiel.xml")
File "/usr/lib/python3.2/xml/etree/ElementTree.py", line 862, in write
serialize(write, self._root, qnames, namespaces)
File "/usr/lib/python3.2/xml/etree/ElementTree.py", line 978, in _serialize_xml
_serialize_xml(write, e, qnames, None)
File "/usr/lib/python3.2/xml/etree/ElementTree.py", line 978, in _serialize_xml
_serialize_xml(write, e, qnames, None)
File "/usr/lib/python3.2/xml/etree/ElementTree.py", line 978, in _serialize_xml
_serialize_xml(write, e, qnames, None)
File "/usr/lib/python3.2/xml/etree/ElementTree.py", line 978, in _serialize_xml
_serialize_xml(write, e, qnames, None)
File "/usr/lib/python3.2/xml/etree/ElementTree.py", line 976, in _serialize_xml
write(_escape_cdata(text))
File "/usr/lib/python3.2/xml/etree/ElementTree.py", line 845, in write
_raise_serialization_error(text)
File "/usr/lib/python3.2/xml/etree/ElementTree.py", line 1091, in _raise_serialization_error
"cannot serialize %r (type %s)" % (text, type(text).__name__)
TypeError: cannot serialize [None, None] (type list)
Zuletzt geändert von Anonymous am Sonntag 15. Januar 2012, 16:35, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Hallo und Willkommen im Forum!

Als erstes mal einige allgemeine Anmerkungen:

- Bei einem so langen Quellcode lagere den doch in ein Pastebin aus; entweder das im Board integrierte (Link oben in der Menüzeile!) oder auf das beliebte paste.pocoo.org.

- Benutze bei Python-Code auch die Python-Code-Tags!

- es ist immer schlecht, wenn Du so viel unkommentierten Code hier reinstellst. Da haben die meisten user einfach keine Lust, sich dort reinzulesen. Besser ist es, ein minimales, lauffähiges Beispiel zu generieren, anhand dessen man den Fehler besprechen und lösen kann

Zum Problem: Man müsste sich da jetzt ziemlich stark in den Code einlesen, um dem Problem direkt auf die Spur zu kommen. Hast Du denn einen Verdacht, wo Du etwas falsches in den Baum einfügst? Zudem haben wir die Ausgangsdatei nicht. Vermutlich packst Du irgend wo eine Liste in eine `text`-Property - wäre jetzt meine Vermutung. Kommentiere doch mal alle Operationen aus. Dann kommnetierst Du sie Stück für Stück wieder ein, bis der Fehler auftritt. So kannst Du den Fehler eingrenzen.

Noch ein paar generelle Anmerkungen:

- Was genau machst Du da? Wenn ich das richtig intepretiere, hast Du eine XML-Datei, die Du verändern willst? Oder aber willst Du eine komplett neue XML-Struktur aufbauen und nutzt dazu nur weniger Elemente der Ursprungsdatei? Je nach Aufgabenstellung ist Dein Ansatz da evtl. eher suboptimal.

- Du benutzt den typischen Anfänger Anti-Pattern:

Code: Alles auswählen

for i in range(0, len(user) - 1):
Man kann in Python direkt über Elemente iterieren!

Code: Alles auswählen

for item in iterable:
    # item ist hier das aktuelle Element
Brauchst Du dennoch zusätzlich einen Index, so nutze `enumerate`:

Code: Alles auswählen

for index, item in enumerate(iterable):
    pass
So wie ich das sehe, sind Deine Datenstrukturen aber auch schlecht gewählt! Wenn Du drei oder vier Listen hast, die alle die gleiche Länge haben und deren einzelne Elemente miteinander in Beziehung stehen (function, picture, name und user), dann baue daraus doch eine Liste von Listen oder eine Liste von Dictionaries. Das ist viel sinnvoller, als den Bezug nur implizit abzubilden (in Deinem Falle eben durch die Länge der Listen und damit dem gleichen Index):

Code: Alles auswählen

# so in der Art machst Du es
user = ["Hyperion", "Lysander"]
pw = ["geheim", "noch_geheimer"]
avatar = ["lego_icon.png", None]
# "merge" alle zusammengehörige Einträge; Zusammenhang nur indirekt über gleichen Index
for i in range(len(user)):
    print user[i], pw[i], avatar[i]

# besser so von Anfang an zusammenfassen (Liste von Dicts):
users = [
    {"user": "Hyperion", "pw": "geheim", "avatar": "lego_icon.png"},
    {"user": "Lysander", "pw": "noch_geheimer", "avatar": None}
]
for user in users:
    print user["user"], user["pw"], user["avatar"]

# oder (Liste von Listen):
users = [
    ["Hyperion", "geheim", "lego_icon.png"],
    ["Lysander", "noch_geheimer", None]
]

for user in users:
    name, pw, avatar = user
    print name, pw, avatar
    # oder
    print ", ".join(*user)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
JustinJ
User
Beiträge: 14
Registriert: Sonntag 15. Januar 2012, 15:59

Also erste Frage: Hauptsächlich geht es darum, drei funktionen zu schaffen. eine soll die XML-Konfiguration, die andere die XML-History auslesen und die dritte soll es alles in einer XML-Datei, wobei variabeln verändert sein könnten, speichern.

da hab ich noch eine frage. das problem ist ja, er muss in der XML auch auf alte Elemente der Liste zugreifen können und sie in die XML reinspeichern. deswegen wollte ich es als 1. Element 2. Element 3. Elements listen. Oder gibt es dafür auch eine andere Lösung?



Edit: Achja, ich will nicht unhöflich erscheinen. Danke für diese tolle Hilfe :)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Kapiere ich alles nicht! Von welcher XML-Struktur redest Du? Wer ist "er"?

Vielleicht gibst Du mal ein minimales Beispiel der XML-Strukturen?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@JustinJ: Du hast offenbar irgendwo den `text` eines Knotens auf eine Liste gesetzt die zwei `None`-Elemente enthält. Jetzt musst Du nur noch heraus finden wo. Dabei könnte es vielleicht helfen den Quelltext sauberer umzuschreiben. Ohne das Datenstrukturen auf Modulebene verändert werden, mit richtigen Funktionen, die Werte als Argumente übergeben bekommen und Ergebnisse als Rückgabewerte haben. Statt auf den globalen Strukturen zu operieren.

`read_configuration()` ist komplett sinnfrei, weil es keinen Unterschied macht, ob man das aufruft oder nicht. Da werden nur ein Haufen lokaler Namen an Werte gebunden, aber nirgends verwendet.

Es drängt sich der Verdacht auf, dass mehrere Listen „parallel” Daten enthalten, die eigentlich elementweise zusammen gehören. Die sollte man deshalb auch nicht getrennt speichern, sondern in einem Objekt zusammen fassen und in einer Liste halten.

Dann braucht man in `write_element()` auch den Index `i` nicht. Ist das Absicht, dass das letzte Element in `user` (und damit auch den anderen „parallelen“ Listen) *nicht* verarbeitet wird?

Warum legst Du in `write_element()` die ganzen Listen vor der Schleife an? Die werden zwar mit Werten gefüllt, *die* werden dann aber nicht wirklich verwendet.
JustinJ
User
Beiträge: 14
Registriert: Sonntag 15. Januar 2012, 15:59

Die XML-Liste ich geb sie mal lieber vollständig.

Code: Alles auswählen

<?xml version="1.0" encoding="UTF-8"?>

<dgraphconfig>
  <configuration>
    <position>
      <xpos>52</xpos>
      <ypos>44</ypos>
    </position>
    <resolution>
      <resx>1024</resx>
      <resy>760</resy>
    </resolution>
    <lastuser>mustermann</lastuser>
    <lastusage>43989723</lastusage>
    <serialcode>QQQZ4BATMAN</serialcode>
  </configuration>
  <history>
    <function>
      <date>20120103163122</date>
      <data>x^2+2x+3</data>
      <picture>
        <name></name>
        <base64 format="jpg"></base64>
      </picture>
      <user>mustermann</user>
    </function>
    <function>
      <date>20120103163123</date>
      <data>x^2</data>
      <picture>
        <name></name>
        <base64 format="jpg"></base64>
      </picture>
      <user>kkister</user>
    </function>
  </history>
</dgraphconfig>
Die Variabeln werden in anderen Funktionen und klassen verwendet, deswegen gibt es das read_ extra.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ähem... was soll uns diese XML-Datei so alleine nützen? Es fehlt ja die Zielstruktur und die Beschreibung, wie man diese aus der obigen Struktur erhalten soll!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
JustinJ
User
Beiträge: 14
Registriert: Sonntag 15. Januar 2012, 15:59

also mein problem zur schleife ist folgendes.

mach ich das so wie oben gegeben, kommt:

Code: Alles auswählen

>>> test = {'user':'tester', 'user': 'tester2'}
>>> print(test)
{'user': 'tester2'}
der speichert nur dann das letzte?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

JustinJ hat geschrieben:also mein problem zur schleife ist folgendes.

mach ich das so wie oben gegeben, kommt:

Code: Alles auswählen

>>> test = {'user':'tester', 'user': 'tester2'}
>>> print(test)
{'user': 'tester2'}
der speichert nur dann das letzte?
Nee - aber Du überschreibst in Deinem Dict ja den Eintrag zum Schlüssel "user" ;-)

Du hast vermutlich keinen Plan von Dictionaries? -> Python-Grundlagen dazu im Tutorial lernen!

Ich vermisse irgend wie die Antwort(en) auf meine Frage...
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
JustinJ
User
Beiträge: 14
Registriert: Sonntag 15. Januar 2012, 15:59

also die XML-Zielstruktur ist es genau dieselbe Liste, wie sie von beginn an wiederrauszubekommen. Man soll lediglich nur die werte ersetzen oder in der historie neue funktionen hinzufügen.

PS: Dictionaries, schaue sie mir gerade im internet an, weiß schon wo der fehler bei mir war danke :)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

JustinJ hat geschrieben:also die XML-Zielstruktur ist es genau dieselbe Liste, wie sie von beginn an wiederrauszubekommen. Man soll lediglich nur die werte ersetzen oder in der historie neue funktionen hinzufügen.
Du mischst mir zu viele Begriffe! "Liste" im Kontext von Python ist eine interne Datenstruktur. Ich vermute, Du beziehst Dich aber mit "Liste" hier auf die XML-Struktur?

Man bekommt also am Ende strukturell den gleichen XML-Baum, nur mit anderen Werten an bestimmten Stellen?

Was sind "die" Werte? Wie kommt man auf die?

Evtl. kann man das aus Deinem Code herauslesen, aber mal im Ernst: Darauf habe ich keine Lust! Du könntest das doch einfach in wenige Sätzen, anhand von simplen kleinen Beispiele treffend erläutern. Wenn Du darauf keine Lust hast bitte. Aber ich bezweifel im Moment ganz stark, dass Dein Ansatz der ideale ist. Liege ich mit meiner Vermutung oben richtig, dann gibt es viel elegantere Möglichkeiten, das Umzusetzen!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
JustinJ
User
Beiträge: 14
Registriert: Sonntag 15. Januar 2012, 15:59

Also Beispiel:

Es ist eine Art taschenrechner:

Der Benutzer A gibt eine Funktion x^2 ein.

Die Funktion wird in der historie gespeichert mit dem ergebnis und der umwandlung also den Bild

Läd der Benutzer das Programm wieder kann man es aus der XML wieder auslesen

Benutzer kann die letzte Funktion wieder auslesen.

Kann auch die Funktion verändern und dann wieder speichern.

Hoffe ich hab mich jetzt nicht zu umständlich ausgedrückt.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

*seufz*
JustinJ hat geschrieben:Also Beispiel:
...
Wenn Du uns jetzt noch beschreibst, wie das alles im Kontext zu der XML-Struktur und den einzelnen Elementen steht, dann wären wir glücklich ;-)

Ist das so schwer nachzuvollziehen, worauf wir hinaus wollen? Wir haben hier doch alle keine Ahnung, womit Du Dich beschäftgist! Für Dich ist vieles einfach implizit klar - für uns nicht. Da musst Du schon genau beschreiben, wie die Zusammenhänge liegen...

Neben den immer noch offenen Fragen, wage ich es dennoch mal eine weiter zu stellen: Wieso willst Du auf Dateiebene am XML etwas manipulieren? Wieso serialisierst Du den Zustand nicht direkt aus dem Programm heraus :K
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
JustinJ
User
Beiträge: 14
Registriert: Sonntag 15. Januar 2012, 15:59

also...

Code: Alles auswählen

  <configuration>
    <position>
      <xpos>52</xpos>
      <ypos>44</ypos>
    </position>
    <resolution>
      <resx>1024</resx>
      <resy>760</resy>
    </resolution>
    <lastuser>mustermann</lastuser>
    <lastusage>43989723</lastusage>
    <serialcode>QQQZ4BATMAN</serialcode>
  </configuration>
hier wird die programmkonfiguration (Auflösung und position auf dem bildschirm), letzter benutzer... reingespeichert...

Code: Alles auswählen

  <history>
    <function>
      <date>20120103163122</date>
      <data>x^2+2x+3</data>
      <picture>
        <name></name>
        <base64 format="jpg"></base64>
      </picture>
      <user>mustermann</user>
    </function>
    <function>
      <date>20120103163123</date>
      <data>x^2</data>
      <picture>
        <name></name>
        <base64 format="jpg"></base64>
      </picture>
      <user>kkister</user>
    </function>
  </history>
Dort die Funktion selber.

achja: Es ist so vorgegeben, dies mit einer XML Datei zu veranstalten, einen sogenannten XML-Parser zu bauen. Das ist eine Aufgabenstellung zu einem Semesterprojekt.

Vorgangsweise ist es einen grafischen Taschenrechner aufzubauen.

Ich möchte gerne die Datei neu speichern, das heißt sobald sie fertig ist im programm eine neue XML-Datei erzeugen, bzw. die alte löschen.
BlackJack

@JustinJ: Warum fängst Du beim Serialisierungs-Format an? Sollten die Datenstrukturen, die im Programm verwendet werden, nicht im Mittelpunkt stehen? Und vielleicht auch erst einmal saubere Programmierung die a) nicht auf globale Datenstrukturen setzt und b) auch funktioniert. Ich habe nämlich den Verdacht, dass Du meine Frage bezüglich der `read_*`-Funktion nicht verstanden hast. Die ist sinnfrei *weil sie nichts bewirkt*. Es macht für das Programm absolut keinen Unterschied ob Du sie aufrufst oder nicht!

Wenn die Datenstrukturen für das Programm (halbwegs) feststehen, *dann* kannst Du dafür Funktionen schreiben, die sie aus XML erstellen oder daraus XML erzeugen.

Ist die XML-Struktur vorgegeben? Falls nein, würde ich einige Namen eventuell ändern und aus einigen Elementen die recht sicher nicht mehr unterteilt werden Attribute machen.
JustinJ
User
Beiträge: 14
Registriert: Sonntag 15. Januar 2012, 15:59

also

Code: Alles auswählen

def write_element():
    read_configuration()
    read_history()

das hier ist sinnfrei?


hmmm, wie soll ich sonst die daten aus der XML laden?

PS: Sie sollen ja auch wiederverwendet werden.
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

Also ein write im Funktionsnamen zu haben, wenn da nur was gelesen wird ist sinnlos.
JustinJ
User
Beiträge: 14
Registriert: Sonntag 15. Januar 2012, 15:59

das kommt später auch wieder weg ist nur zum test...


ich hab jetzt die dictionary eingebaut und yeah es funktioniert :)) Daaaanke!
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

JustinJ hat geschrieben:also

Code: Alles auswählen

def write_element():
    read_configuration()
    read_history()
das hier ist sinnfrei?
Beispiel:

Code: Alles auswählen

In [23]: a = 1

In [24]: def foo():
    a = 42
    print(a)
   ....:     

In [25]: foo()
42

In [26]: a
Out[26]: 1
Wenn Du Objekte in einer Funktion an einen Namen bindest, so ist dieser Name nur im jeweiligen Scope gültig. Das `a` ist auf globaler Ebene bei mir gleich 1. Innerhalb von `foo` binde ich die 42 an `a` - aber das ist ein lokales `a`! Nach Auruf der Funktion ist das äußere `a` immer noch an den Wert 1 gebunden.

Bei Dir ist das nicht anders...

Du musst Dich mal mit Funktionen und Rückgabewerten auseinander setzen!
JustinJ hat geschrieben: hmmm, wie soll ich sonst die daten aus der XML laden?
Wie BlackJack schon sagte solltest Du erst einmal die internen Datenstrukturen festlegen! (Also meinetwegen eine Klasse "User" o.ä.). Wenn die alle feststehen und sinnvoll implementiert sind, dann kannst Du Dir Funktionen schreiben, die diese Objekte serialisieren.

Momentan stocherst Du im Nebel und vor allem gehst Du planlos vor!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
JustinJ
User
Beiträge: 14
Registriert: Sonntag 15. Januar 2012, 15:59

danke erstmal für die hilfe. bin erstmal froh, dass es überhaupt funktioniert :)


und am sonsten werde ich morgen nochmal alles durchlesen und ein paar sachen verbessern. Das was noch kommt ist eine Klasse, dass ist logisch
Antworten