XML mit mehreren Tables verarbeiten

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
KayJu
User
Beiträge: 7
Registriert: Donnerstag 29. April 2021, 06:46

Donnerstag 29. April 2021, 12:52

Hallo,
Wenn es hier falsch ist, habt bitte Nachsicht mit mir, ich bin neu in diesem Forum.

Ich habe ein Problem mit dem auslesen einer XML Datei.
Die Datei, welche ich verwenden möchte, besteht aus mehreren Tables, (6 Stück) in Table 3 ändert sich jedoch der Inhalt von der Anzahl her. Nun bin ich auf der Suche nach einer Möglichkeit, am besten aus der xml immer nur eine table zu importieren, und diese dann zu verarbeiten.

Hier ein Muster des Aufbaus mit 2 Tables:

Code: Alles auswählen

<?xml version="1.0" encoding="UTF-8"?>
<Table name="Namen">
<Data type="STRING" header="Name1"/>
<Data type="STRING" header="Name2"/>
<Data type="STRING" header="Name3"/>
<Data type="STRING" header="Name4"/>
<Data type="STRING" header="Name5"/>
<Row>
</Row>
<Row>
<Column value="Datensatz_Name1"/>
<Column value="Datensatz_Name2"/>
<Column value="Datensatz_Name3"/>
<Column value="Datensatz_Name4"/>
<Column value="Datensatz_Name5/>
<Table name="Farbe">
<Data type="STRING" header="Farbe1"/>
<Data type="STRING" header="Farbe2"/>
<Data type="STRING" header="Farbe3"/>
<Row>
</Row>
<Row>
<Column value="Rot"/>
<Column value="Gelb/>
<Column value="Gruen"/>
</Row>
</Table>
Mein bisheriger versuch:

Code: Alles auswählen

from xml.dom import minidom


xmldoc = minidom.parse('Test.xml')


itemlist = xmldoc.getElementsByTagName('Column') 

print(len(itemlist))


Name1 = itemlist[0].attributes['value'].value
print(Name1)

Name2 = itemlist[1].attributes['value'].value
print(Name2)
Auf diese Weise bekomme ich hard codiert alle Daten aus dieser einen xml eingelesen, da ich nach dem Inhalt der einzelnen columns suche... Allerdings bekomme ich so Probleme, wenn sich eine table in ihrer Anzahl der Datensätze verändert...
Daher mein Wunsch, zum Beispiel nur die 2. Tabelle "Farben" Einzulesen...

Habe da gerade eine ziemliche "Denkblockade"... vielleicht kann mir ja jemand helfen...
Dankeschön :-)
Sirius3
User
Beiträge: 14428
Registriert: Sonntag 21. Oktober 2012, 17:20

Donnerstag 29. April 2021, 13:14

Das was Du da zeigst, ist kaputtes XML. Das ist wenig hilfreich, wenn man nicht den Aufbau der XML-Datei kennt.

minidom verwendet man nicht, sondern ElementTree. Dann sucht man auch nicht nach allen Columns, sondern geht die Baumstruktur der XML-Datei durch.
Aber da Du ja deine XML-Datei nicht zeigst, kann man da nur raten: Du gehst die Table-Elemente durch, suchst von da nach Row-Elementen und nimmst dann deren Column-Elemente.
Column scheint so eigentlich sowas wie Cell zu sein. Wer hat denn das XML-Format erfunden?
KayJu
User
Beiträge: 7
Registriert: Donnerstag 29. April 2021, 06:46

Donnerstag 29. April 2021, 15:58

Entschuldige bitte, habe es bisher erfolgreich geschafft mich vor der Arbeit mit XML "zu drücken" da ich das Format schrecklich finde...

Die komplette Originaldatei kann ich leider nicht teilen, da es sich um sensible Daten handelt. Ich habe hier die einzelnen Einträge mal durch xxx ersetzt. Sie sollte aber komplett sein.
Die Datei bekomme ich so zugeschickt und muss die dann auswerten und die darin enthaltenen Daten weiter verteilen auf ander API's.
Vielleicht hilft das ja mehr.

Code: Alles auswählen

<?xml version="1.0" encoding="UTF-8"?>
<Table name="xxxx">
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Row>
</Row>
<Row>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx "/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx "/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Table name="xxxx">
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Row>
</Row>
</Table>
<Table name="xxxx">
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Row>
</Row>
</Table>
<Table name="xxxx">
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Row>
</Row>
<Row>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
</Row>
</Table>
<Table name="xxxx">
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Row>
</Row>
</Table>
<Table name="xxxx">
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Row>
</Row>
<Row>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
</Row>
<Row>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
</Row>
<Row>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
</Row>
</Table>
</Row>
</Table>

Sirius3
User
Beiträge: 14428
Registriert: Sonntag 21. Oktober 2012, 17:20

Donnerstag 29. April 2021, 16:17

Es ist also so, dass ein Table in einer Row einer anderen Table vorkommen kann?
Nach welchen Kriterien sind denn die Tabellen ineinander verschachtelt?
Bleibt natürlich die allgemeine Aussage, dass Du den Baum durchlaufen mußt.
Wie soll denn die Ausgabe aussehen?
KayJu
User
Beiträge: 7
Registriert: Donnerstag 29. April 2021, 06:46

Donnerstag 29. April 2021, 20:19

Am liebsten hätte ich so etwas in der Art:
Daten1 = "Column value"
sodass ich mit dem Wert der "Zelle" weiterarbeiten kann
Sirius3
User
Beiträge: 14428
Registriert: Sonntag 21. Oktober 2012, 17:20

Donnerstag 29. April 2021, 20:37

die Beschreibung ist für mich völlig unverständlich. Von welcher Zelle redest Du?
KayJu
User
Beiträge: 7
Registriert: Donnerstag 29. April 2021, 06:46

Donnerstag 29. April 2021, 21:32

also ich verstehe die xml so:
Das was im "Data type="STRING" header="xxxx" ist die Bezeichung der Date, und was in der "row" darunter steht "Column value="xxxx" ist der Wert, den ich haben will...


Wenn ich mir mal diese Table als muster nehme:

Code: Alles auswählen

<Table name="xxxx">
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Data type="STRING" header="xxxx"/>
<Row>
</Row>
<Row>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
<Column value="xxxx"/>
</Row>
</Table>
habe ich ja 8 Header und 8 Values... die Values will ich haben...

(Entschuldige bitte, wenn ich mich etwas kompliziert ausdrücke, habe "Zelle" geagt, da ich hierbei eine "excel Tabelle" vor meinem Inneren Auge habe)
__deets__
User
Beiträge: 9685
Registriert: Mittwoch 14. Oktober 2015, 14:29

Donnerstag 29. April 2021, 22:22

Das ist schon so richtig, passt nur nicht mit deinem Wunsch, Daten1 zu bekommen. Denn es ist eine Liste von Listen. Also

Code: Alles auswählen

[
["A", "B"],
[1, 2],
[3, 4],
]
"Herr Fachmann, wie bohre ich mir ein Loch ins Knie?"

"Das sollten sie nicht tun! Und wenn man operiert, muss man auf Hygiene achten, und nicht einen Bohrer, der gerade in der Wand ein Loch gebohrt hat, nehmen."

"Das war nicht meine fachliche Frage!!"
Sirius3
User
Beiträge: 14428
Registriert: Sonntag 21. Oktober 2012, 17:20

Freitag 30. April 2021, 08:49

Um an die Daten der obersten Tabelle zu kommen, braucht es nur eine doppelte Schleife:

Code: Alles auswählen

import xml.etree.ElementTree as et

tree = et.ElementTree(file='xx.xml')
root = tree.getroot()
for row in root.findall('Row'):
    cells = [cell.attrib['value'] for cell in row.findall('Column')]
    print(cells)
KayJu
User
Beiträge: 7
Registriert: Donnerstag 29. April 2021, 06:46

Freitag 30. April 2021, 10:10

Danke, in die Richtung hatte ich mich gestern Abend auch noch versucht. Die Idee mit der doppelten Schleife ist gut. Die Listenausgabe gefällt mir auch besser als minidom...

Irgendwie schaffe ich es aber nicht über die erste Table hinaus, die anderen zu finden.

Ist mein Gedankengang da jetzt richtig:
Ich würde eine "dreifache Schleife" bauen, als erstes nach "Table" suchen, und danach dann die rows und Cells?
Sirius3
User
Beiträge: 14428
Registriert: Sonntag 21. Oktober 2012, 17:20

Freitag 30. April 2021, 10:15

Ja, wenn Du die anderen Tabellen finden möchtest, brauchst Du drei Schleifen.
KayJu
User
Beiträge: 7
Registriert: Donnerstag 29. April 2021, 06:46

Montag 3. Mai 2021, 10:46

Ich muss leider nochmal nerven...

Code: Alles auswählen

for table in root.findall('Table'):
    for row in table.findall('Row'):
        cells = [cell.attrib['value'] for cell in row.findall('Column')]
        print(cells)
Ist mein Denkansatz so richtig? Bzw. besser, was mache ich falsch, dass die Ausgabe mir nichts raus gibt?

bzw. irgendwie müsste ich dem ja auch die Indexnummer der Tabelle geben, welche ich gerade durchsuchen möchte.. Würde das so versuchen:

Code: Alles auswählen

for table in root.findall('Table'):
    for row in table[1].findall('Row'):
        cells = [cell.attrib['value'] for cell in row.findall('Column')]
        print(cells)
oder besser anders?
Benutzeravatar
__blackjack__
User
Beiträge: 8573
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Montag 3. Mai 2021, 11:00

@KayJu: Warum musst Du die Indexnummer der Tabelle angeben? `table` ist jeweils die Tabelle die gerade verarbeitet wird. Also wenn `root.findall("Table")` denn Ergebnisse hätte. Das sucht *im* `root` nach *direkten* <Table>-Kindknoten. Die gibt es aber nicht, deshalb wird auch nichts verarbeitet.
“Dawn, n.: The time when men of reason go to bed.” — Ambrose Bierce, “The Devil's Dictionary”
KayJu
User
Beiträge: 7
Registriert: Donnerstag 29. April 2021, 06:46

Montag 3. Mai 2021, 11:12

Weil die XML ja mehrere Tables hat, und ich gerne Die Daten geziehlt aus einer Table ziehen möchte. wenn ich jetzt zum Beispiel aus Tabelle 3 Die Daten brauche, dass ich nicht in Tabelle 2 suche... Deshalb hätte ich jetzt über eine Indexierung nachgedacht...
Sirius3
User
Beiträge: 14428
Registriert: Sonntag 21. Oktober 2012, 17:20

Montag 3. Mai 2021, 11:25

Ein komplexes Problem löst man dadurch, dass man es in mehrere Schritte aufteilt. Den Teil, die Daten aus einer Table herauszulesen, hast Du schon, jetzt mußt Du Dich darauf konzentrieren, die das richtige Table-Element zu finden. In Deinem Beispiel-XML sind die Tables im zweiten Row-Element.
Antworten