ElementTree (XML) speichert alles in eine Zeile?

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.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@kaineanung: Du wurdest aber drei Mal auf den korrekten Aufruf hingewiesen, wenn ich mich nicht verzählt habe! Das hat nicht einmal mehr mit dem Lesen der Doku zu tun, sondern lediglich dem "korrekten" Abschreiben ;-) Denn cofi hatte Dir ja netter Weise bereits alles präsentiert...
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Sirius3
User
Beiträge: 17753
Registriert: Sonntag 21. Oktober 2012, 17:20

@kaineanung: es sollte halt das TRY im Vordergrund stehen. Du mußt hier ja nicht hunderte Seiten Dokumentation lesen, sondern nur ein paar Beispiele, die man einfach kopieren, verstehen und abwandeln kann. Dazu noch die Beschreibung von wenigen Funktionen, die man auch sofort brauchen kann.
kaineanung
User
Beiträge: 145
Registriert: Sonntag 5. April 2015, 20:57

@Sirius3

Ich habe mein Code an dein Beispiel angepasst und es funktioniert.

Dir und all den anderen vielen Dank für die Mühe!

So hat es also geklappt:

Code: Alles auswählen

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

import xml.etree.ElementTree as etree
from xml.dom import minidom

def prettify(elem, indent="  ", level=0):
    i = "\n" + level*indent
    if len(elem):
        if not elem.text or not elem.text.strip():
            elem.text = i + indent
        for el in elem:
            prettify(el, indent, level+1)
        if not el.tail or not el.tail.strip():
            el.tail = i
    if not elem.tail or not elem.tail.strip():
        elem.tail = i
    
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):
    prettify(root)
    etree.ElementTree(root).write(xmlFileName,encoding="utf-8")
@cofi

Ich habe den Code aufgeräumt :)
Sirius3
User
Beiträge: 17753
Registriert: Sonntag 21. Oktober 2012, 17:20

Zum Dritten mal, was soll denn der Sinn der Funktionen xmlopen, xmladd oder xmlwrite sein?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Du hast ja immer noch eine Abhängigkeit zu ``minidom`` drin... ich persönlich finde das auch besser, als die eigene ``prettify`` Funktion, aber aktuell ist das überhaupt nicht sinnvoll.

Solange du noch ``global`` in Deinem Code hast, ist er nicht aufgeräumt...

Die Namen finde ich auch nicht gut... ``xmladd``... was soll denn da "geadded" werden? Das "xml"-Präfix ist insofern sinnlos, als dass es sich aus dem Kontext ergibt, daß es sich um XML zentrierte Funktionen handelt. Interessant wäre es aus dem Namen zu erfahren, *was* hinzugefügt wird!

Und die ``write`` Funktion schreibt gar nichts, sondern formatiert irgendwie einen ``etree.Element``.

Wie ich gerade gesehen habe arbeitet ``prettify`` rekursiv... alleine das macht sie für mich unbrauchbar!
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

@sirius
Zum Dritten mal, was soll denn der Sinn der Funktionen xmlopen, xmladd oder xmlwrite sein?
Ähm, ich habe die Funktionen in ein Modul ausgelagert. Irgendwie muss ich ja vom Hauptprogramm diese aufrufen?
Und da ist mir nichts besseres eingefallen als Funktionen zu schreiben die mir schon vom Namen her sagen was diese machen.

xmlopen -> erstellt ein Objekt von root-Element (Name bei mir: root) und ein tree-Element (Name bei mir: etree)

xmladd -> Fügt ein Node hinzu. Erwartet 2 Argumente. 1. Arg: Name des anzulegeneden Nodes 2.Arg: Inhalt (text) des Nodes

xmlwrite -> Erstellt die XML-Datei und re-parsed das etree zufor mit prettify. Erwartet 1 Argument: Name der XML-Datei welche erstellt wird

Ich verstehe nicht ganz deine Frage. Ist das falsch? Ich sagte bereits am Anfang: geplant war eine Klasse aus alldem zu bilden.

@Hyperion
etree.ElementTree(root).write(...) -> erstellt/schreibt die XML-Datei?
Die Benamsung ist aber sowieso momentan temporär. Ich habe das geschrieben was mir gerade so eingefallen ist. Wenn ich die Funktionen habe die mir ein Element un ein SubElement erstellen, dann wird alles umgestellt. Wie gesagt: geplant war eine Klasse in welcher ich dann im Konstruktor das Element-Obj und das tree-obj erstelle. Dann habe ich auch Klassenweit bekannte Objekte wo das 'public' enfallen wird.
Das hier soll nur dazu dienen die Methoden von etree schnell kennen zu lernen (quasi quick&dirty).

Zu prettify:
kann ich absolut nichts zu sagen! Ich habe es hier vorgeschlagen bekommen und bin schon heilfroh darüber das ich es auf die Reihe bringen konnte das es funktioniert... Danke dafür nochmals an alle!
Sirius3
User
Beiträge: 17753
Registriert: Sonntag 21. Oktober 2012, 17:20

@Hyperion: Dir ist bewußt, dass minidom auch rekursiv arbeitet?

@kaineanung: also nochmal: xmlopen arbeitet mit global, auch wenn es das nicht machen würde, wird tree nicht gebraucht und somit ist xmlopen = Element. xmladd, ist wie schon geschrieben SubElement(root, name).text = wert, hat also auch keinen Mehrwert, außerdem erscheint root aus dem nichts.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Sirius3 hat geschrieben:@Hyperion: Dir ist bewußt, dass minidom auch rekursiv arbeitet?
Nö. Aber... Iiiiihhh bäääähh :twisted:
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, um zu beweisen daß ich mit den komischen Funktionen und Objekte, global noch dazu, wirklich nur experimentieren wollte (ist eben echt schnell und einfach es so zu machen) habe ich jetzt daraus eine Klasse erstellt.
Die ist, hoffe ich, zufriedenstellend zumal wenn man bedenkt was für ein Anfänger ich bin :)

Code: Alles auswählen

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

import xml.etree.ElementTree as ET

class MyXML(object):
    
    def __init__(self, rootname):
        self.__root = ET.Element(rootname)
        self.__element = ET.ElementTree(self.__root)
        
    def add_node(self, nodename, value):
        node = ET.Element(nodename)
        self.__root.append(node)
        node.text=value
    
    def add_subnode(self, subnodename, new_nodename, value=""):
        parent_node = self.__root.find(subnodename)
        tmp_node = ET.SubElement(parent_node, new_nodename)
        if value <> '': tmp_node.text = value
        
    def write(self, xmlFileName):
        self.prettify(self.__root)
        ET.ElementTree(self.__root).write(xmlFileName,encoding="utf-8")
        
    def prettify(self, elem, indent="  ", level=0):
        i = "\n" + level*indent
        if len(elem):
            if not elem.text or not elem.text.strip():
                elem.text = i + indent
            for el in elem:
                self.prettify(el, indent, level+1)
            if not el.tail or not el.tail.strip():
                el.tail = i
        if not elem.tail or not elem.tail.strip():
            elem.tail = i
Kein minidom, keine globalen Objekte, keine mehrfach-importierung, etwas sprechendere Funktionsnamen (Methoden) (wenn es auch nur klitzklein besser ist) usw.

Ach ja, warum ich das mache und nicht gleich 'nur' etree also Objekt in meinem 'Haupt'-Code verwende?
Weil ich dadurch Schritt für Schritt lerne und erkenne was für das aktuell gebrauchte Vorhaben wichtig ist aus der Vielfalt an Methoden von etree.
Und weil ich es 'kapseln' kann um meinen 'Hauptcode' übersichtlicher behalten zu können.

Ich hoffe das ist jetzt nichts schlimmes oder der Gleichen?
Sirius3
User
Beiträge: 17753
Registriert: Sonntag 21. Oktober 2012, 17:20

@kaineanung: was soll das My-Präfix? Was sollen die doppelten Unterstriche? self.__element heißt nicht nur falsch, sondern ist auch unnötig. <> ist schon seit Python 2.0 deprecated. add_node benutzt immer noch kein SubElement.
kaineanung
User
Beiträge: 145
Registriert: Sonntag 5. April 2015, 20:57

@sirius3
was soll das My-Präfix?
Wie soll ich es denn sonst nennen? XML ist es eben nicht weil es nur etwas speziell für mich angepasstes ist. Liegt dann nahe es 'My' zu benennen + das was es beinhaltet (eben doch ein Teilausschnitt von XML). Ausserdem ist die Benennung ja 'sythax-unkritisch' solange es aussagekräftig ist. Und Geschmackssache....
Was sollen die doppelten Unterstriche?
Ich dachte so definiert man private Eigenschaften und Methoden? Unnd ich will das Node-Objekt und das Tree-Bojekt eben nur privat in der Klasse haben. Was ist daran falsch? Was auch immer es ist: sagt es mir damit ich es in Zukunft besser machen kann. Ich hätte nur gedacht das da nichts falsches drann wäre...
self.__element heißt nicht nur falsch, sondern ist auch unnötig
Sehe ich auch gerade. Ich erstelle ein Member-Objekt und benutze es nirgends weil ich die gewünschten Nodes ja nach Anforderung erstelle und 'was auch immer damich mache'.
Ok, wird entfernt.
<> ist schon seit Python 2.0 deprecated
Oh, ok, habe ich nun in != umgewandelt. Bei mir mixen sich gerade mehrere Programmiersprachen...
add_node benutzt immer noch kein SubElement
Ok, jetzt muss ich zugeben: verstehe ich ganz und gar nicht obwohl du mich immer wieder darauf ansprichst! Warum sollte add_Node ein Subelement benutzen?
Ich erstelle ja kein Sub-Node sondern ein Node der obersten Ebene? Oder muss man das gar nicht so unterscheiden? Wenn nicht, dann kann ich das add_node ja ganz weglassen udn immer add_subnode benutzen mit dem Parent-Element 'root'. Wenn ich mir das so recht überlege: warum eigentlich nicht sofern das so geht? Oder meinst du was anderes?
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Namen sind halt eben kein Ausdruck deiner Kreativitaet, sondern sollen etwas aussagen. Das Problem mit "My" ist, dass es nichts zur Aussagekraft beisteuert.

Man kennzeichnet "private" Namen mit einem (1) fuehrenden Unterstrich, zwei (2) dienen zur Vermeidung von Namenskollisionen bei Mehrfachvererbung.

Daneben `prettify` ist semantisch keine Methode, mache daraus wieder eine Funktion.
kaineanung
User
Beiträge: 145
Registriert: Sonntag 5. April 2015, 20:57

@cofi
Man kennzeichnet "private" Namen mit einem (1) fuehrenden Unterstrich, zwei (2) dienen zur Vermeidung von Namenskollisionen bei Mehrfachvererbung.
Aha, ok. Also nur ein Unterstrich. Wird erledigt.
Man kennzeichnet "private" Namen mit einem (1) fuehrenden Unterstrich, zwei (2) dienen zur Vermeidung von Namenskollisionen bei Mehrfachvererbung.
Ich habe gedacht mit dem einfachen Unterstrich deutet man eine 'Halb-Private' Variable/Methode an. Das man die sozusagen nicht ändern soll aber darf. Aber ok, habei ch auch diesbezüglich was gelernt...

Bei google habe ich gesucht nach 'python class private variables' und folgendes bei 'stackoverflow' gefunden:
Double underscore. That mangles the name. The variable can still be accessed, but it's generally a bad idea to do so.

Use single underscores for semi-private (tells python developers "only change this if you absolutely must") and doubles for fully private.
Daher dachte ich ich mach mal eine ganz private daraus. Aus der Programmierersprache in der ich halbwegs 'fit' bin kenne ich sowas in der Art ja nicht...
Egal, wird jetzt und in Zukunft umgesetzt :)
Daneben `prettify` ist semantisch keine Methode, mache daraus wieder eine Funktion.
Und das mache ich indem ich self nicht mehr übergebe? Die Funktion erwartet aber dennoch dann ein Parameter mehr... wie deklariere ich die Funktion dann als solche damit sie keien Methode wird?
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Wenn dir der Unterschied zwischen Funktion und Methode nicht klar ist, dann arbeite am besten (nochmal) das Python Tutorial durch.
Das spricht uebrigens auch die privaten Namen an:
https://docs.python.org/3/tutorial/classes.html#private-variables hat geschrieben:“Private” instance variables that cannot be accessed except from inside an object don’t exist in Python. However, there is a convention that is followed by most Python code: a name prefixed with an underscore (e.g. _spam) should be treated as a non-public part of the API (whether it is a function, a method or a data member). It should be considered an implementation detail and subject to change without notice.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

kaineanung hat geschrieben:Bei google habe ich gesucht nach 'python class private variables' und folgendes bei 'stackoverflow' gefunden:
Stackoverflow ist so eine Sache. Das Punktsystem und die Popularität führen dazu, dass viele Leute sehr schnell und entsprechend unüberlegt auf möglichst viel Antworten. Die Qualität der Antworten ist dementsprechend im Laufe der Zeit ziemlich gefallen, vorallem bei Detailfragen im Kontext von irgendwelchen populären Themen. Wenn du sowas hast frag in themenspezifischen Communities nach, für Python halt hier oder auch in IRC Channels wie #python und #python.de im freenode Netzwerk.
kaineanung
User
Beiträge: 145
Registriert: Sonntag 5. April 2015, 20:57

@cofi

Du meinst sicherlich daß die Funktion im gleichen Modul (Datei) aber ausserhalb der Klasse gespeichert werden soll?
Dann hätte ich ja eine Funktion statt einer Methode. Ich weiß lediglich nicht ob die dann in der Klasse 'sichtbar' wäre. Das muss ich eben ausprobieren oder diese dann als global deklarieren falls nicht sichtbar. Dann buht ihr mich aber aus weil global geht gar nicht...

Und laut python-tutorial sind Funktionen in einer Klasse eben Methoden. Und explizit Funktionen in der Klasse geht ja nicht..... oder habe ich was verpasst? Darum war ich stutzig und mir ist der Unterschied einer Funktion zu einer Methode durchaus bewusst.
BlackJack

@kaineanung: Funktionen in einer Klasse geht schon — nennt sich `staticmethod()`.

Wenn Du die Funktion auf Modulebene definierst dann ist die wie jeder Name auf Modulebene innerhalb des Moduls sichtbar und von aussen entweder per Punkoperator über das Modul oder man kann den Namen explizit importieren.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Du hast `global` nicht verstanden. Mit `global` erreicht man, dass der deklarierte Name nicht im lokalen Namensraum definiert wird, sondern eben im globalen.
`global` ist deswegen "boese", weil man keine globalen veraenderlichen _Daten_ haben will, die sollten Funktionen/Methoden eben ueber Parameter betreten und ueber Rueckgabewerte verlassen.

Das macht mit Funktionen aber keinen Sinn, denn entweder man definiert sie schon global, d.h. auf oberster Ebene, oder sie sollten es eben nie sein, z.B. bei `lambda`s.

Generell gilt: Wenn du dir unsicher bist, ob etwas funktioniert (und es nicht nachschlagen willst oder finden kannst), dann teste es doch einfach ;)
kaineanung
User
Beiträge: 145
Registriert: Sonntag 5. April 2015, 20:57

@BlackJack

Cool, also war meine vermutung richtig... vielleicht wir ja noch was aus mir :wink:

@cofi

Wie ich habe es nicht verstanden mit dem 'globalen deklarieren'?

Ich denke schon:

Variable im deklarierter Namensraum = sichtbar in diesem Namensraum
Variable ausserhalb des Namensraumes deklariert = nicht sichtbar in diesem Namensraum
Beim Letzteren: ausser es ist global deklariert und dann eben über alle Namensräume sichtbar

Also, sichtbar und nicht sichtbar sind meine Worte....
Und diese definitin stimmt doch so oder nicht?
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Nein das stimmt so nicht. Sichtbar ist alles, was in uebergeordneten Namensraeumen definiert ist.

Code: Alles auswählen

def foo(x):
    def bar()
        return x
    return bar
`x` ist nicht im Namensraum von `bar` definiert, ist aber trotzdem zugaenglich.
Der Punkt bei `global` ist, dass es um das _aendern_ geht, statt im aktuellen Namensraum definierst du damit im globalen Namensraum.

Code: Alles auswählen

def foo():
    global x
    x = 42
Ist eben das gleiche wie wenn ich diese Zuweisung direkt toplevel schreibe.
Antworten