Listenelemente in XML in best. Reihenfolge einfügen

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.
Daniela
User
Beiträge: 73
Registriert: Donnerstag 19. Juni 2008, 07:32

Listenelemente in XML in best. Reihenfolge einfügen

Beitragvon Daniela » Donnerstag 12. März 2009, 09:50

Hallo alle miteinande,

ich bräuchte mal wieder Hilfe. :oops:
Ich habe eine XML-Datei, diese soll nun mit Hilfe von Python erweitert. Also neue Knoten mit entsprechenden Inhalt. Dabei will ich aber das bestimmte vorhandene Knoten entfernt werden.
In der Doku zu ElementTree hab ich die Methode '__delitem__' und '__delslice' gefunden, nur weiß ich grad nicht so wirklich, wie ich das einsetzen kann.

Des Weiteren hab ich mehrdimensionales Array, deren Inhalt in die XML eingetragen werden soll. Dabei soll innerhalb eines Tags 2 Elemente des Arrays eingefügt werden. das aktuelle sowie das folge Element.

Hier ist erstmal mein bisher vorhandener Programmcode.

Code: Alles auswählen

#-*- coding: utf8 -*-
from xml.etree import ElementTree as etree

bsp_liste = ((0, 12, 26), (1, 54, 42), (2, 47, 21), (4, 12, 324), (5, 111, 0), (6, 111, 44), ...)
dateipfad = "datei.xml"
doc = open(dateipfad, 'rw')
tree = etree.parse(doc)
root = tree.getroot()
kats = tree.getroot().find("kategorien")
haupknoten_1 = tree.getroot().find("hauptknoten")

for i, a, b in bsp_liste:
        kat = etree.SubElement(kats, id="id%d" %i, name="BSP%d" %(i+1)
        punkt = etree.SubElement(kat, x="%d" %x, y="%d" %y

for i, a, b in bsp_liste:
   unterknoten = etree.SubElement(hauptknoten, "unterknoten", end_id="id%d" %(i+1), start_id="id%d" %i)
   unter_unterknoten_1 = etree.SubElement(unterknoten, "untereEbene", a="%d" %a, b="%d" %b)
   unter_unterknoten_2 = etree.SubElement(unterknoten, "untereEbene", a="%d" %a, b="%d" %b)

etree.dump(root)
doc.write(root)
doc.close()

Wie gesagt es sollen als erstes die vorhandenen Elemente innerhalb des Knotens "Kategorien" gelöscht/entfernt werden, um dann den Inhalt des Arrays einzufügen. Bis auf das Löschen funktioniert das auch.
Dabei besteht jedes Listenelement des Arrays aus einer ID, X- und Y-Koordinaten.
Im Code (oben) werden mir ja bisher im entsprechenden Tag 2 mal die Punktkoordinaten eingefügt, aber jedes mal bisher die beiden aktuellen, ich will aber das aktuelle und das folge Element.
Hat jemand eine Idee?

Die XML-Datei soll dann später in dieser Form gespeichert werden.

Code: Alles auswählen

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beispiel SYSTEM "beispiel.dtd">
<wurzel version="1.2">
  <kategorien>
    <kategorie>
       <punkt x="12" y="26"/>
   </kategorie>
   <kategorie>
      <punkt x="54" y="42"/>
   </kategorie>
   <kategorie>
      <punkt x="88" y="55"/>
   </kategorie>
   ...
  </kategorien>
  <hauptkategorie>
    <unterknoten>
     <untereEbene x="12" y="26"/>
     <untereEbene x="54" y="42"/>
   </unterknoten>
   <unterknoten>
     <untereEbene x="54" y="42"/>
     <untereEbene x="47" y="21"/>
   </unterknoten>
   ...
  </hauptkategorie>
</wurzel>


Vielen Dank schon mal

Daniela
Benutzeravatar
Hyperion
Moderator
Beiträge: 7471
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Beitragvon Hyperion » Donnerstag 12. März 2009, 11:01

In der Doku zu itertools findet sich folgendes Rezept:

Code: Alles auswählen

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return izip(a, b)

Damit sollte das Problem mit den Pärchen gelöst sein.

Zum Löschen gibt es laut Doku bei ElementTree Elment.remove(subelement). Somit sollte das auch leicht zu machen sein. In Deinem Fall müßtest Du also entweder über die Childelemente von <kategorien> iterieren und das entsprechend aufrufen, oder vermutlich besser unterhalb von wurzel das child <kategorien> selber löschen und diesen Knoten danach neu generieren.
Daniela
User
Beiträge: 73
Registriert: Donnerstag 19. Juni 2008, 07:32

Beitragvon Daniela » Donnerstag 12. März 2009, 11:26

Aha ok, ich versuch es mal mit dem ``remove()``, also dass ich einmal komplett alles in dem Zweig "Kategorien" lösche.

Code: Alles auswählen

kats = tree.getroot().find("kategorien")
etree.Element("kategorien").remove("kategorien")


Aber wenn ich das nach dem Schema mache, dann bekomme ich folgendes:

[code=]File "*\punkte_zeichnen.py", in line 34 in <module>
etree.Element("kategorien").remove("kategorien")
File "C:\Python\25\lib\xml\etree\ElementTree.py", line 309, in remove
assert iselement(element)
AssertionError
[/code]

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

Beitragvon Leonidas » Donnerstag 12. März 2009, 11:29

Ich denke der Parameter für ``remove()`` muss ein ElementTree-Element sein und kein String.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Daniela
User
Beiträge: 73
Registriert: Donnerstag 19. Juni 2008, 07:32

Beitragvon Daniela » Donnerstag 12. März 2009, 11:39

Wenn ich in ``remove()`` das Element "kats" einfüge, welches ich vorher bestimmt habe/gefunden habe,

Code: Alles auswählen

kats = tree.getroot().find("kategorien")
etree.Element("kategorien").remove(kats)


bekomme ich einen ValueError
[code=]File "C:\Python\25\lib\xml\etree\ElementTree.py", line 309, in remove
self._children.remove(element)
ValueError: list.remove(x): x not in list[/code]

Oder muss man das vielleicht ganz anders machen?

Daniela
BlackJack

Beitragvon BlackJack » Donnerstag 12. März 2009, 11:40

@Daniela: Du erzeugst ein Element und versuchst davon einen Kindknoten zu entfernen. Wie sollte das auch funktionieren!?
Daniela
User
Beiträge: 73
Registriert: Donnerstag 19. Juni 2008, 07:32

Beitragvon Daniela » Donnerstag 12. März 2009, 12:06

Also in der XML-Datei die durch ein anderes Programm erstellt wird, ist der Knoten "kategorien" schon mit 3 Werten gefüllt. Das heißt der Ast "Kategorie" wurde schon 3mal geschrieben.
Diese will ich erstmal entfernen um sie dann neue Äste mit den Werten der Liste zu füllen.
Wobei eigentlich theoretisch die ersten 2 Listenwerte übernommen werden können und der 3 geändert werden soll, sowie die weiteren Werte eingefügt werden.

Oder gibt es vielleicht irgendeine Funktion, mit welcher man bestimmte Unterknoten updaten kann? Das würde ja auch schon reichen.

Aber ich glaube dass es einfacher wäre erstmal die vorhandenen Knoten (kategorie) zu löschen um dann neue einzufügen.

Und da ja schon festgestellt wurde, dass einzelne Elemente vorher noch durchiteriert werden müssten, wollte ich gleich den Ast "kategorien" löschen
Einfach ausgedrückt, sieht die XML am Anfang so aus
[code=]
wurzel
a
b
c
\b
b
c
\b
b
c
\b
\a
d
\d
\wurzel
[/code]

An sich sollen die einzelnen b-Tags entfernt werden, aber um es sich einfacher zu machen, soll gleich das gesamte a-Tag gelöscht werden um dann neu erstellt zu werden.

Daniela
Benutzeravatar
snafu
User
Beiträge: 5388
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Beitragvon snafu » Donnerstag 12. März 2009, 12:11

Daniela hat geschrieben:Wenn ich in ``remove()`` das Element "kats" einfüge, welches ich vorher bestimmt habe/gefunden habe,

Code: Alles auswählen

kats = tree.getroot().find("kategorien")
etree.Element("kategorien").remove(kats)


Ich bin nicht ganz so sicher im Umgang mit `ElementTree`, aber ich glaube dein Code findet das, was im Knoten `kategorien` steht, erzeugt anschließend ein Element `kategorien' und versucht daraus etwas zu entfernen (was aber nicht vorhanden ist, weil du das Element ja gerade erst neu erzeugt hast). Eigentlich willst du wahrscheinlich mit dem Suchergebnis, das an `kats` gebunden ist, weiterarbeiten und davon etwas entfernen. Also tu das auch. ;)
shcol (Repo | Doc | PyPi)
Daniela
User
Beiträge: 73
Registriert: Donnerstag 19. Juni 2008, 07:32

Beitragvon Daniela » Donnerstag 12. März 2009, 12:22

ich glaub, da ich sowieso fast alles aus der alten datei lösche, kann ich die xml dann auch gleich komplett neu erstellen und nicht nur zusätzlich was einfügen. Ich denke das ist dann fast noch die einfachste Methode.

Trotzdem bleibt ja dann immernoch das 2. Problem/Fragestellung aus meinem 1. Post, nämlich wie bekomme ich das aktuelle und das Folgeelement ausgelesen/eingefügt.

Den Tipp von Hyperion hab ich mir auch schon angesehen, nur weiss ich nicht so recht, wo und wie ich es einsetzte.
Hat da jemand eine Idee/Hinweis?

Daniela
Benutzeravatar
snafu
User
Beiträge: 5388
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Beitragvon snafu » Donnerstag 12. März 2009, 12:44

Daniela hat geschrieben:wie bekomme ich das aktuelle und das Folgeelement ausgelesen/eingefügt.


Ich weiß nicht genau, was du damit meinst. Falls es das erste und zweite Element im Code sein soll, würde mir spontan `findall()` einfallen, wo man dann das Element mit Index 0 bzw 1 rausfischt. Vielleicht gibt es als elegantere Methode ja auch so etwas wie `next()` bzw die Möglichkeit, einen Iterator zu erstellen, von dem man ein Element weiter springen kann. Das hätte den Vorteil, dass du nicht erst unnötigerweise eine Liste mit allen Elementen erstellen müsstest, wo du genau weiß, dass dich eigentlich nur die beiden ersten Elemente interessieren. Vielleicht missverstehe ich dich aber auch und du meinst etwas ganz anderes. :D ;)
shcol (Repo | Doc | PyPi)
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Donnerstag 12. März 2009, 12:45

Daniela hat geschrieben:Hat da jemand eine Idee/Hinweis?

Mit lxml ist das ziemlich trivial, dort hat jedes Element einfach eine ``getnext()``-Methode, mit der man das nachfolgende Element auf der selben Ebene bekommt.

snafu: ``findall()`` findet alle Elemente die dem Query entsprechen, diese müssen nicht umbedingt nachfolgend sein. Zudem man mit den beschränkten Abfragemöglichkeiten von ElementTree AFAIK nicht genau festlegen dass nur die Kindelemente eines bestimmten Knotens in das Ergebnis aufgenommen werden können - ich kann mich da aber auch irren und ElementTree kann mehr als ich dachte.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Daniela
User
Beiträge: 73
Registriert: Donnerstag 19. Juni 2008, 07:32

Beitragvon Daniela » Donnerstag 12. März 2009, 13:00

@snafu

ich will von meiner Liste bei jedem Schleifendurchlauf jeweils das aktuelle und das nächste Element aus der Liste ausgelesen haben
Vereinfacht mal an folgendem Beispiel:
Bsp: my_list = (1,2,3,4,5,6)
[code=]1. Durchlauf (ausgelesen):
1
2
2. Durchlauf(ausgelesen):
2
3
3. Durchlauf (ausgelesen):
3
4
4. Durchlauf (ausgelesen):
4
5
5. Durchlauf (ausgelesen):
5
6[/code]
In meinem Fall gesteht jedes einzelne Element aus ein einem Tripel, wobei mich aber lediglich pro Tripel nur die Werte 1 und 2 interessieren.

@Leonidas
funktioniert das auch mit einem array? Ich meine ich hätte gern wie oben schon beschrieben aus meiner Liste das aktuelle und folge Element, damit dieses dann in die xml-Datei eingetragen wird.

grüße

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

Beitragvon Leonidas » Donnerstag 12. März 2009, 13:06

Daniela hat geschrieben:funktioniert das auch mit einem array?

Nein, erstens ist das was du Array nennst eine Liste und zweitens geht das nur für lxml-ElementTrees.

Daniela hat geschrieben:Ich meine ich hätte gern wie oben schon beschrieben aus meiner Liste das aktuelle und folge Element, damit dieses dann in die xml-Datei eingetragen wird.


Nimm einfach Hyperions Beispiel, das ist doch nicht so schwer:

Code: Alles auswählen

from itertools import tee, izip

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return izip(a, b)

a = range(10)
print list(pairwise(a))
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Daniela
User
Beiträge: 73
Registriert: Donnerstag 19. Juni 2008, 07:32

Beitragvon Daniela » Donnerstag 12. März 2009, 14:19

Wenn ich den Code mal testweise ausführe, nur um zu sehen, ob es auch das macht, was ich will bekomme ich folgendes:

[code=]Traceback (most recent call last):
File "M:\Testscripte\meine_liste.py", line 11, in <module>
print list(pairwise(a))
File "M:\Testscripte\meine_liste.py", line 7, in pairwise
next(b, None)
NameError: global name 'next' is not defined[/code]

und jetzt?

Ich hatte jetzt schon überlegt, dass ich neben der 1. for-Schleife noch eine 2. darin durchlaufen lasse, in diese dann immer vom Index her um 1 weiter ist.
Nur da bekomme ich dann einen IndexError (list index out of range)

Code: Alles auswählen

for i, a, b in bsp_liste:
   unterknoten = etree.SubElement(hauptknoten, "unterknoten", end_id="id%d" %(i+1), start_id="id%d" %i)
   unter_unterknoten_1 = etree.SubElement(unterknoten, "untereEbene", a="%d" %a, b="%d" %b)
       for k in range(len(bsp_liste)):
            unter_unterknoten_2 = etree.SubElement(unterknoten,
            "untereEbene", a="%d" %(bsp_liste[k+1][1]), b="%d" %(bsp_liste[k+1][2]))
Zuletzt geändert von Daniela am Donnerstag 12. März 2009, 14:27, insgesamt 1-mal geändert.
Benutzeravatar
keppla
User
Beiträge: 483
Registriert: Montag 31. Oktober 2005, 00:12

Beitragvon keppla » Donnerstag 12. März 2009, 14:26

Daniela hat geschrieben:Wenn ich den Code mal testweise ausführe, nur um zu sehen, ob es auch das macht, was ich will bekomme ich folgendes:
und jetzt?


probiere mal b.next() statt next(b, None).

Wer ist online?

Mitglieder in diesem Forum: kbr, noisefloor