XML-Dateien einlesen

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
Papp Nase
User
Beiträge: 139
Registriert: Dienstag 11. März 2014, 15:12

Guten Tag,

ich möchte gerne eine XML-Datei einlesen und habe dazu die Funktionen verwendet, die ich hier gefunden habe:

http://docs.python.org/2/library/xml.dom.html

Die Test-XML-Datei sieht so aus:

Code: Alles auswählen

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Messwerte>
    <Einleitung>
        <Intro>Hallo</Intro>
        <Suppe>Kartoffelsuppe</Suppe>
    </Einleitung>
    <Daten>
        <Zeit>10:00</Zeit>
        <Messwert1>345</Messwert1>
        <Messwert2>234</Messwert2>
        <Messwert3>1264</Messwert3>
    </Daten>
    <Daten>
        <Zeit>11:00</Zeit>
        <Messwert1>345</Messwert1>
        <Messwert2>234</Messwert2>
        <Messwert3>1264</Messwert3>
    </Daten>
    <Daten>
        <Zeit>12:00</Zeit>
        <Messwert1>345</Messwert1>
        <Messwert2>234</Messwert2>
        <Messwert3>1264</Messwert3>
    </Daten>
    <Daten>
        <Zeit>13:00</Zeit>
        <Messwert1>345</Messwert1>
        <Messwert2>234</Messwert2>
        <Messwert3>1264</Messwert3>
    </Daten>
    <Daten>
        <Zeit>14:00</Zeit>
        <Messwert1>345</Messwert1>
        <Messwert2>234</Messwert2>
        <Messwert3>1264</Messwert3>
    </Daten>    
</Messwerte>
Ich möchte gerne die Werte auslesen, die in Zeit, Messwert1, Messwert2 und Messwert3 stehen. Ich muss mich dabei von Ebene zu Ebene durcharbeiten und habe dazu ein kleines Programm geschrieben:

Code: Alles auswählen

#!/usr/bin/env python

from xml.dom import minidom

XMLDatei = minidom.parse ("test.xml")

Ebene1 = XMLDatei.getElementsByTagName("Messwerte")
Ebene2_Namen = Ebene1[0].childNodes
for  Namen in Ebene2_Namen:
    print Namen
Mit diesem Programm bekomme ich die Namen aller Child-Objekte von Messwerte angezeigt. Diese Elemente nenne ich Ebene2.

Die Child-Objekte Einleitung und Daten haben ihrerseits ja auch wieder Child-Objekte, die ich Ebene3 nennen möchte.

Die Print-Anweisung gibt eine hex-Adresse heraus:

Code: Alles auswählen

<DOM Element: Einleitung at 0x12334>
<DOM Element: Daten at 0x124555334>
.
.
.
Dort steht also eine Adresse. Die Print-Anweisung ist ja in der for-Schleife.
Jetzt muss ich irgendwie mit dieser Adresse auf das Element verweisen.

Ich habe dieses Programm dazu versucht:

Code: Alles auswählen

#!/usr/bin/env python

from xml.dom import minidom

XMLDatei = minidom.parse ("test.xml")

Ebene1 = XMLDatei.getElementsByTagName("Messwerte")
Ebene2_Namen = Ebene1[0].childNodes
for  Namen in Ebene2_Namen:
    print Namen
    Ebene2 = Ebene1[0].getElementsByTagName(Namen)
    print "Ebene2: ---> " + str(Ebene2)
    Ebene3_Namen = Ebene2.childNodes
    print Ebene3_Namen
Dieses Programm funktioniert so in dieser Form nicht. Ich habe versucht, nach dem Element in Ebene2 in Ebene1 zu suchen, um dann daraus die Namen zu bekommen. Ich weis leider nicht, wie ich es hinbekomme, dass ich darauf zugreifen kann.

Falls mir jemand von Euch helfen könnte, wuerde ich mich sehr darueber freuen.
BlackJack

@Papp Nase: Tu Dir selbst einen Gefallen und vergiss DOM ganz schnell wieder. Die `ElementTree`-API (`xml.etree`) ist wesentlich schöner zu benutzen.

Die ``print``-Anweisungen geben Dir die Elemente aus. So sehen die halt aus wenn man sie nach ihrer Zeichenkettendarstellung fragt. Du willst ja wahrscheinlich auch nicht die Elemente selber ausgeben, sondern die Werte der Textknoten in den Elementen.

Was ist das denn für ein Format? Sind die Tagnamen für <Messwert> tatsächlich durchnummeriert? Das wäre eine unsinnige Idee, denn dann kann man danach nicht mehr suchen. Die Elemente haben ja implizit schon eine Reihenfolge das muss man nicht extra numerieren. Ansonsten kann man eine zusätzliche Nummerierung als Attribut einführen.

Edit: Hier sieht man warum die nummerierten Messwertnamen blöd sind, weil man sich nicht mehr einfach alle Elemente mit einem bestimmten Tag geben lassen kann, sondern tatsächlich alle durchgehen und den Tagnamen manuell prüfen muss:

Code: Alles auswählen

#!/usr/bin/env python
from xml.etree import ElementTree as etree


def main():
    document = etree.parse('test.xml')
    for data_node in document.findall('Daten'):
        print data_node.find('Zeit').text
        for child_node in data_node:
            if child_node.tag.startswith('Messwert'):
                print ' ->', int(child_node.text)


if __name__ == '__main__':
    main()
Papp Nase
User
Beiträge: 139
Registriert: Dienstag 11. März 2014, 15:12

Vielen Dank für Deinen Hinweis, dann versuche ich mal das mit dem Elemttree.
Black Jack hat geschrieben:Was ist das denn für ein Format? Sind die Tagnamen für <Messwert> tatsächlich durchnummeriert? Das wäre eine unsinnige Idee, denn dann kann man danach nicht mehr suchen. Die Elemente haben ja implizit schon eine Reihenfolge das muss man nicht extra numerieren. Ansonsten kann man eine zusätzliche Nummerierung als Attribut einführen.
Was meinst Du damit? Meinst Du damit, weil ich in der Beispieldatei die Messwerte Messwert1, Messwert2 und Messwert3 genannt habe? Falls ja, so könnte dort z.B. auch Temperatur, Wasserstand und irgendetwas stehen, es ist doch ein Beispiel.
Benutzeravatar
/me
User
Beiträge: 3561
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Papp Nase hat geschrieben:Meinst Du damit, weil ich in der Beispieldatei die Messwerte Messwert1, Messwert2 und Messwert3 genannt habe? Falls ja, so könnte dort z.B. auch Temperatur, Wasserstand und irgendetwas stehen, es ist doch ein Beispiel.
Wir können hier nicht ahnen, was nur ein Beispiel und was möglicherweise echte Daten sind.

Der Punkt ist, dass das von dir gezeigte XML-Fragment eine Nummerierung der Tagnamen aufweist und so etwas ist fast bei jedem Einsatz falsch. Auf so etwas weist man lieber einmal zu viel als einmal zu wenig hin.

Wenn es sich dabei um unterschiedliche Daten handelt, dann ist nichts dagegen zu sagen.

Code: Alles auswählen

<data>
    <time>11:00</time>
    <temperature>345</temperature>
    <pressure>234</pressure>
    <humidity>1264</humidity>
</data>
Ich würde die Zeit allerdings vermutlich als Attribut des data-Nodes modellieren.
Papp Nase
User
Beiträge: 139
Registriert: Dienstag 11. März 2014, 15:12

/me hat geschrieben: Der Punkt ist, dass das von dir gezeigte XML-Fragment eine Nummerierung der Tagnamen aufweist und so etwas ist fast bei jedem Einsatz falsch. Auf so etwas weist man lieber einmal zu viel als einmal zu wenig hin.
Hmm, ich muss gestehen, dass ich eigentlich garnicht verstehe, worum es hierbei geht. Heisst das so, dass in den TagNamen gar keine Zahlen vorkommen duerfen? Also Messwert1, Messwert2 und Messwert3 ist verboten? Oder bei drei gleichen Temperaturmessfuehlern z.B., darf ich dann da auch nicht schreiben

Temperatur1, Temperatur2, Temperatur3?
Papp Nase
User
Beiträge: 139
Registriert: Dienstag 11. März 2014, 15:12

Hallo BlackJack,

vielen Dank, dass Du mir ein kleines Beispielprogramm angefügt hast, ich habe mich sehr darüber gefreut.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Nein, aber meistens ist Nummerierung unnötig. Wenn du mehre Messungen hast, dann schreibst du die in einer Folge auf:

Code: Alles auswählen

<measurement value="..."/>
<measurement value="..."/>
<measurement value="..."/>
<measurement value="..."/>
Damit hast du eine Reihenfolge. Wenn du keine Reihenfolge gegeben hast, sonder, wie in deinem Fall drei verschiedene Sensoren, dann solltest du dazu Attribute verwenden:

Code: Alles auswählen

<sensor id="1">
    <measurement value="..."/>
    <measurement value="..."/>
    <measurement value="..."/>
</sensor>
<sensor id="2">
    <measurement value="..."/>
    <measurement value="..."/>
    <measurement value="..."/>
</sensor>
Durchnummerieren ist beim Programmieren meistens eine schlechte Idee. Meistens ist das ein Zeichen, dass die gewählte Datenstruktur falsch ist.
Das Leben ist wie ein Tennisball.
Benutzeravatar
/me
User
Beiträge: 3561
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Papp Nase hat geschrieben:Hmm, ich muss gestehen, dass ich eigentlich garnicht verstehe, worum es hierbei geht. Heisst das so, dass in den TagNamen gar keine Zahlen vorkommen duerfen?
Dürfen dürfen sie schon, aber sollen sollten sie nicht. In den Namen sollten keine Dinge hinein, die man anders sinnvoller ausdrücken kann.
Papp Nase hat geschrieben:Oder bei drei gleichen Temperaturmessfuehlern z.B., darf ich dann da auch nicht schreiben

Temperatur1, Temperatur2, Temperatur3?
Ungut. Im Endeffekt sind das alles Temperaturen und es gibt keine Notwendigkeit da noch eine Zahl anzuhängen. Wenn sie durch unterschiedliche Sensoren entstanden sind, dann wäre das hier eine Lösung:

Code: Alles auswählen

<data>
    <time>11:00</time>
    <temperature sensor="abc">345</temperature>
    <temperature sensor="fgh">359</temperature>
    <temperature sensor="zyxw">281</temperature>
</data>
Merkst du worauf wir hinaus wollen? Ich kann mir so ohne Probleme alle Temperaturen holen. Ich kann auch nach dem Sensor filtern. Mit deinem Ansatz musst du explizit unterschiedlich durchnummerierte Daten suchen und bei einer Erweiterung um einen weiteren Sensor wird es dann noch garstiger. Für mich würde sich da nichts ändern.

Wenn es noch nicht klar ist, dann frag noch mal nach.
Antworten