etree - Subelement hinzufü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.
kaineanung
User
Beiträge: 145
Registriert: Sonntag 5. April 2015, 20:57

Hallo Leute,
ich hätte da mal wieder ein Problem:

Ich habe als Beispiel folgende XML:

Code: Alles auswählen

<stadt>
    <name>München</name>
    <Einwohner>1992929</Einwohner>
    <Fläche></Fläche>
</stadt>
Jetzt möchte ich aber Untergruppen erstellen wie z.B.:

Code: Alles auswählen

<stadt>
    <daten>
        <name>München</name>
        <Einwohner>1992929</Einwohner>
        <Fläche></Fläche>
    </daten>
    <irgendwas>
        <elem1>blah</elem1>
    </irgendwas>
</stadt>
Wie ich nun die ganzen 'Tags' erstelle mit etree ist mir klar. Aber wie ich diese Gruppen bilde leider nicht?
Wie mache ich so eine Gruppe 'daten' oder 'irgendwas'?
Habe natürlich schon mit SubElement experimentiert. Aber das Beispiel, welches ich gefunden habe über google, hat mir was anderes gemacht als das was ich wollte.

Daher, befor ich mich zu Tode experimentiere, frage ich euch:
ist SubElement das richtige und wenn ja, wie bekomme ich die o.g. Struktur hin?
SubElement ertwartet 2 Parameter. Ich glaubte das erste wäre das Parentelement und das zweite der Name des Childelementes. Ich habe mich geirrt denn das erste war der Name eines 'normalen' Elmentes (also ein neues Element das in gleicher Ebenen hinzugefügt wird) und der zeite Parameter ein Attribut!
Also bei der verwendung des SubElementes habe ich sowas erhalten:

Code: Alles auswählen

<stadt>
    <name>München</name>
    <name1 daten="irgendwas">
    <Einwohner>1992929</Einwohner>
    <Fläche></Fläche>
</stadt>
Dann habe ich mich wohl geirrt und das SubElement hat mich aufgrund dessen Namens etwas fehlgeleitet...

Könnt ihr mir da bitte helfen?

Ich Danke euch schon einmal im Voraus für eure Mühe!
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Code: Alles auswählen

In [31]: top = Element('top')

In [32]: SubElement(top, 'x')
Out[32]: <Element 'x' at 0x7fae72aa9bd0>

In [33]: SubElement(top, 'y')
Out[33]: <Element 'y' at 0x7fae72aa9b50>

In [34]: SubElement(top, 'z')
Out[34]: <Element 'z' at 0x7fae72aa9c50>

In [35]: etree.dump(top)
<top>
  <x />
  <y />
  <z />
</top>
`SubElement` tut doch genau das, was du willst?
Und nochmal: Zeige den Code mit dem du ein Problem hast.

Ich hatte dir das PyMOTW zu ElementTree doch schonmal verlinkt, arbeite das mal durch.
kaineanung
User
Beiträge: 145
Registriert: Sonntag 5. April 2015, 20:57

@cofi

Wo kein Code da kann ich nichts zeigen (ich gebe mir ja mühe und habe ja wenigstens schön die XML-Struktur in mehrfacher ausführung gepostet :D )

Ich kann aber ncohmals das Modul, welches bei mir für xml zuständig ist und erweitert werden soll mit diesen SubElementen, posten:

Code: Alles auswählen


#!/usr/bin/env python
# -*- coding: UTF-8 -*-

from xml.etree.ElementTree import ElementTree
from xml.etree.ElementTree import Element, SubElement
import xml.etree.ElementTree as etree
from ElementTree_pretty import prettify

def xmlopen(rootElement):
    global root
    global tree
    root=etree.Element(rootElement)
    tree=etree.ElementTree(root)

def xmladd(name, wert):
    name=etree.Element(name)
    root.append(name)
    name.text=wert
        
def xmlwrite(xmlFileName):
    tree.write(open(xmlFileName,'w'))
    #with open(xmlFileName,'w') as f:
        #f.write(prettify(tree))

(xmlwrite schreibt immer noch den 'Einzeiler' weil das mit dem Prettify bei mir Fehler bringt und nicht klappt -> ElementTree kennt keinen 'tag' oder irgendwie so... ist aber ein anderes Problem das ich im anderen Thread 'verfolgen' werde. Hier gehts um SubElement)
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

kaineanung hat geschrieben:(xmlwrite schreibt immer noch den 'Einzeiler' weil das mit dem Prettify bei mir Fehler bringt und nicht klappt -> ElementTree kennt keinen 'tag' oder irgendwie so... ist aber ein anderes Problem das ich im anderen Thread 'verfolgen' werde. Hier gehts um SubElement)
Ich komm mir ja irgendwie verarscht vor. Ich habe dir das in dem anderen Thread _zweimal_ erklaert, dass du `prettify` falsch benutzt, sogar mit Code der es richtig verwendet.
Sirius3
User
Beiträge: 18335
Registriert: Sonntag 21. Oktober 2012, 17:20

@kaineanung: irgendwie wiedersprechen sich die beiden Zitate:
kaineanung hat geschrieben:Also bei der verwendung des SubElementes habe ich sowas erhalten:
kaineanung hat geschrieben:Wo kein Code da kann ich nichts zeigen
Die ElementTree dokumentation hat genug Beispiele, wie man es richtig anwendet, und Deine "Funktionen" (absichtlich in Anführungszeichen) habe ich schon im anderen Thread kommentiert.
kaineanung
User
Beiträge: 145
Registriert: Sonntag 5. April 2015, 20:57

@cofi

Wenn du dir verarscht vokommst dann liegt es vielleicht daran das du dich nicht in meine Lage hinenversetzen kannst?
Ich bin eben noch sehr sehr neu in Python und muss ständig googeln um auch nur die kleinsten Schritte voranzukommen. Wahrscheinlich habe ich nicht verstanden das ich das prettify falsch verwende und wieso das ist und wo der Fehler jetzt liegt? In der Funmktion, im Parameter oder an der flaschen Stelle des Aufrufes der Funktion? Oder ist es weil ich das falsche Objekt zugewiesen habe oder weil vielleicht doch der fehler in der XML-Dateistruktur liegt... ist schwer zu erklären aus meiner Sicht, aber ich stehe immern och vor eine dichten Nebelwand die sich nur sporadisch 'lichtet'....
Darum erkenne ich manche sachen wohl noch nicht die für den erfahrenen Python-Programmierer ja total offensichtlich sind....

Das ist, angenommen du kennst dich nicht mit Quentenphysik aus, so als ob du gleich ein Referat zu den Quarks geben musst samt diverser Formeln und du siehst zwar alles vor dir in einem Handbuch, verstehst aber nicht was, wieso und warum?

So schlimm ist es jetzt bei mir nicht, aber irgendwo dazwischen bin ich anzufingen....

@Sirius3

Ich habe 2 py-Dateien welche ich jeweils aufrufe:
einmal eine die zum aktuellen 'Probeprojekt' gehört. Da wo ich zu einem Ziel hinkommen will.
Dann habe ich eine temporäre Test-PY-Datei wo ich geschwind Funktionen, Module und eben allgemeinen Code eingebe um es geschwind zu testen um zu lernen und um zu sehen was dabei so 'rauskommt'.
Die letztere wird ständig geleert und neuer Code eingegeben zum probieren. Da habe ich auch SubElemente ausprobiert. Hat nicht so ganz funktioniert und ich habe mich anderen Problemen im 'Hauptcode' von Python gewidmet (siehe andere Threads mit BeautifulSoup). Dadurch habe ich ja wieder anderen Code, bezogen auf BS in der 'Testdatei' getestet....
Kurz gesagt: in meiner Pythondatei des Projektes gibt es noch keine SubElements. Alles andere ist und war temporär....

Also Sorry wenn ich dich verwirre....

Zu den Beispielen der ElementTree:
Ich habe ja auch Beispiele gefunden (falls es nicht gemerkt wurde: ich komme ja erst hier her wenn ich länger gegoogelt habe und nichts oder nichts funktionierendes oder falsches gefunden habe) die mich ja leider nicht weitergebracht haben.
Ich komme ja auch immer mit: ich habe schon dies und jenes gefunden doch leider ist dies oder jenes falsch UND ich kann es nicht soweit anpassen das es bei mir das gewünschte Resultat bringt..
Ich gebe mir ja Mühe (ich hatte gehofft ihr erkennt das :cry: )
Sirius3
User
Beiträge: 18335
Registriert: Sonntag 21. Oktober 2012, 17:20

@kaineanung: wie kannst Du zu etwas Fragen stellen, das Du schon längst wieder gelöscht hast? Wenn Du Code postest, können wir hier drauf aufbauen. Ohne Code hängt ja alles im leeren Raum. Also mach Deine Versuche mit SubElement erneut, poste den Code, das Ergebnis und das gewünschte Ergebnis, und dann können wir drüber reden.
kaineanung
User
Beiträge: 145
Registriert: Sonntag 5. April 2015, 20:57

@Sirius3

Ok, wird heute Abend gemacht!
Aber dennoch wäre es hilfreich mir zu sagen wie der Grundsätzliche ablauf ist um ein SubElement einzufügen.

node = SubElement(childname, Unternodename)
tree.append(node)
usw...

Also was für ein Objekt ich erstellen muss und wo und wie ich es dann dem ElementTree hinzufüge und ob überhaupt dem ElemenTree oder dem root oder wem auch immer?
Und auch das war mehr geraten denn ich weis nicht was das root-Objekt darstellt (das Dokument selber?) und was das ElementTree und was das Element (vermute das letztere einfach den Node/Tag?)?

Wie du siehst: ich sehe nur schemenhaft die Umrisse duch den dicken Nebel...
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Ich kann mich durchaus in deine Lage versetzen, aber wenn du mir sagst, dass du etwas nicht verstehst, wenn ich es zweimal Schritt fuer Schritt vorgekaut habe, setzt es aus.

Ich glaube dir fehlt ein strukturiertes Vorgehen und hier konkret das Konzept wie "ElementTree" aufgebaut ist. Also: Bitte schau dir das verlinkte MoTW an in dem ElementTree vorgestellt wird.
BlackJack

@kaineanung: Die Fragen sollten eigentlich durch die Dokumentation des `ElementTree`-Moduls beantwortet werden. Da steht das alles inklusive Beispielen und einem kleinen Tutorial.
kaineanung
User
Beiträge: 145
Registriert: Sonntag 5. April 2015, 20:57

Ok, ich habe ein mir ein wenig die Doku von etree duchgelesen.
https://docs.python.org/3/library/xml.e ... ath-syntax

Ich habe es nun so verstanden daß das SubElement beim ersten Argument ein XML-Node als Element-Objekt erwartet.

Das zweite Argument ist dann der Name des neu anzulegenden Elements (als untergeordnetes Element)?

Zurückgeliefert wird ein tree-Objekt was dann ausgegeben oder gespeichert werden kann.
So weit so gut.

Jetzt habe ich folgendes ausprobiert:

Code: Alles auswählen

import xml.etree.ElementTree as ET

a = ET.Element('a')
b = ET.SubElement(a, 'b')

ET.dump(a)
Die Ausgabe zeigt mir an:
<a><b /></a>
Erwartet habe ich aber
<a><b></b></a>
So, was läuft schief? Oder läuft nichts schief nur ich benutze die falschen Werkzeuge, den falschen Weg, die falsche Methode?

Wenn das geklärt wird, dann kommt das nächste:
Ich muss ja zu jeder Zeit an eine bestimmte Stelle der Struktur ein SubElement einfügen können.
Das gewünschte parent-element finde ich dann über root.find('Name_des_Nodes') heraus und der liefert mir dann das Parent-Node zurück? (Das war eine Frage)
Ist das dann so das ich das zurückgelieferte Objekt als erstes Argument bei SubElement angebe?
Sirius3
User
Beiträge: 18335
Registriert: Sonntag 21. Oktober 2012, 17:20

@kaineanung: jetzt fängst Du also endlich an, die Dokumentation zu lesen. Dann mußt Du ja nur noch die XML-Spezifikation lesen, um zu merken, dass beide Repräsentationen identisch sind. Das Unterscheiden von Trees und Nodes solltest Du aber noch besser lernen.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

In XML kann man in der Repräsentation einen leeren Knoten abkürzen, indem man den Slash *hinter* den Namen des Tags vor der schließenden Klammer schreibt.

Das sind natürlich absolute Basics, die vermutlich sogar auf der Wikipedia Seite zu XML zu finden sein sollten... ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
kaineanung
User
Beiträge: 145
Registriert: Sonntag 5. April 2015, 20:57

So, jetzt habe ich alles in eine Klasse umgemodelt und es funktioniert sogar :D

Zum krönenden Abschluss was das erstellen einer XML angeht jetzt folgende Frage:

Wie kann ich einen ganzen Tree-'Zweig' in ein neu anzulegendes SubElement verschieben?

Ich habe als Beispiel folgendes:

Code: Alles auswählen

<root>
<a></a>
<a1><a2>Mein Text</a2></a1>
<b></b>
</root>
Ich möchte den a1-Node (mit seinem SubElement a2) eigentlich komplett in dem a-Node haben.
Jetzt habe ich ein wenig gegoogelt und das Tutorial angeschaut aber nichts entsprechendes gefunden.

Mein Ziel:

Code: Alles auswählen

<root>
<a><a1><a2>Mein Text</a2></a1></a>
<b></b>
</root>
Wenn ihr mir da helfen könntet wäre ich euch sehr dankbar!
vielen Dank für eure Mühe!
kaineanung
User
Beiträge: 145
Registriert: Sonntag 5. April 2015, 20:57

Mache ich das eventuell über die Methode 'insert'?
Mich hat der erste Parameter etwas irritiert weil in der Doku dort eine 0 für Index steht.
Ich habe ja kein Index in dem Sinne sondern ein Node unter welchen ich das andere Node verschieben will.
Ein wenig gegoogelt und gefunden daß das 'Verschieben' zwar so nicht geht aber mit einem Zwischenspeichern des Node-Objektes (welches ich verschieben möchte), des Löschens (remove) des Nodes und anschliessen dem Einfügen des zwischengespeicherten Nodes an die richtige Stelle ich das so managen kann.

Dennoch: die 'Insert'-Methode erwartet an erster Stelle ein Index. Was soll ich dann da reinsetzen? Klar, ein Index. Aber wo finde ich den? Gibt es eine Methode den Index des gewünschten (Ziel-)Nodes zu erhalten?

In meinem Beispiel soll also das komplette <a1> in das <a> verschoben werden.
Also müsste ich demnach
tmp_node = <a1>
remove <a1>
insert (index von <a>, tmp_node)

oder irgendwas in diese Richtung.
Kurz:
ist Insert die Methode die ich benötige? Wenn ja, wie ermittle ich den Index des Zielnodes oder kann ich da einfach das Zielnode als Element selber übergeben?
BlackJack

@kaineanung: Wenn Du nicht weisst an welchem Index Du etwas einfügen möchtest reicht Dir vielleicht die `append()`-Methode die das Element einfach als letztes Kindelement hinten anhängt.
kaineanung
User
Beiträge: 145
Registriert: Sonntag 5. April 2015, 20:57

@BlackJack

Wie ich weiß nicht wo ich es hinzufügen soll?
Doch doch. Nicht das wir aneinander vorbeireden: ich will den <a1>-Node (mitsamt seiner ganzen 'Unterbaum') an dem <a>-Node reinschieben. (siehe mein Besipiel oben)
Also ich weiß schon wohin ich das haben will, nur nicht welche Methode ich dafür benutzen kann.
Insert-Methode (vom etree-Objekt) erwartet als erstes Argument eben ein Index und da bin ich mir nicht sicher ob es die richtige Methode ist und wenn ja, wie ermittle ich den Index vom <a>-Node?
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Code: Alles auswählen

<a1><a2>Mein Text</a2></a1>
`a2` ist das SubElement von `a1`, Klingelt da was?
Mit `append` kannst du das natuerlich auch machen, nur musst du es eben auf dem _richtigen_ Element, naemlich `a1` aufrufen.
kaineanung
User
Beiträge: 145
Registriert: Sonntag 5. April 2015, 20:57

@cofi

Das <a2> das SubElement von <a1> ist, das ist mir doch selbstverständlich klar.

Aber ich habe ja noch das <a>-Element in gleicher 'Ebene' mit dem <a1>.
Ich möchte jetzt das <a1>-Element IN DAS <a>-Element verschieben mitsam des <a2>-SubElements!

Code: Alles auswählen

<root>
<a></a>
<a1><a2></a2></a1>
<b></b>
</root>
Das <a>-Element ist in gleicher Ebene mit dem <a1>-Element. Das <a1>-Element hat noch ein SubElement, nämlich <a2>.
Ich möchte nun <a1><a2></a2></a1> IN DAS <a></a> verschieben.

Also will ich das aus dem genannten Beispiel folgendes wird:

Code: Alles auswählen

<root>
<a><a1><a2></a2></a1></a>
<b></b>
</root>
Wie mache ich das? Insert? Was anderes?

Vielleicht leigt es ja auch in der Darstellung das man es nicht erkennen kann?
Ich versuche es hiermit:
<a></a><a1><a2></a2></a1>
Soll werden zu :
<a><a1><a2></a2></a1></a>
Oder so verdeutlicht:

Code: Alles auswählen

 --a
|
 --a1
|  |
|   --a2
|
 --b
a1 soll verschoeben werden in a:

Code: Alles auswählen

 --a
|   |
|    --a1
|       |
|        --a2
|
 --b
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Oh, dass du du ein existierendes verschieben willst, statt ein neues einzufuegen.
Das ist aber auch das gleiche, nur muss man es halt noch loeschen:

Code: Alles auswählen

In [10]: tostring(top)
Out[10]: '<top><x><y /></x><z /></top>'

In [11]: z = top.find('z')

In [12]: top.remove(z)

In [13]: tostring(top)
Out[13]: '<top><x><y /></x></top>'

In [14]: top.find('x').find('y').append(z)

In [15]: tostring(top)
Out[15]: '<top><x><y><z /></y></x></top>'
Antworten