XML ElementTree Values verarbeiten

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
TheUnreal
User
Beiträge: 4
Registriert: Montag 7. März 2022, 11:53

Hallo zusammen,

ich habe vor langer Zeit in VBA mit dem MSXMLDom eine Schnittstelle geschrieben, die XML-Werkstattdateien einliest,verarbeitet und in einer MsAccess Datenbank ablegt.

Nun sind die Zeiten von Access endlich vorbei und es steht eine neue Lösung ins Haus, die Pythonmodule unterstützt (print("Yeah")) :).

Ich habe mich also mit ElementTree beschäftigt und sehr schnell festgestellt, dass ich mich sehr bequem im XML bewegen kann, aber das Ergebnis ist anders als erwartet. Während ich in Access beim Zugriff auf

Code: Alles auswählen

childNode.Values
den reinen Textwert erhalten habe, bekomme ich bei Python ein

Code: Alles auswählen

dict_values(['81_24629_0'])
. Okay, also nach Dictonary gegoogelt und versucht mich daran zu halten und mit

Code: Alles auswählen

print(xmlData["TRANS_ID"])
direkt an das Ergebnis zu kommen. Das Ergebnis :

Code: Alles auswählen

  
print(xmlData['OWNERSHIP'])
KeyError: 'OWNERSHIP'

Code: Alles auswählen

import xml.etree.ElementTree as ET
import psycopg2
import re

conn = psycopg2.connect("dbname='Odoo' user='odoo' password='HierStandGefährliches^^' host='localhost'")
tree = ET.parse("/Import/Eine.xml")
root = tree.getroot()

#   tag = detail ; text immer NULL ; attrib z.b. {'BUY_DATE': '2021-04-03'}
for child in root:
    for subchild in child:
        xmlData = subchild.attrib
        print(xmlData)  #ergibt eine Liste, die einem Dictonary gleicht aber nicht so nutzbar ist
        #child.attrib.keys sind die Spaltennamen, ...values die Werte
        #Es handelt sich um ein "Dictonary", ein Schlüsselpaar...Ein hoch, dass ich nur 3 Stunden gebraucht habe das zu kapieren...
        #https://www.python-kurs.eu/python3_dictionaries.php <--- für die doofen unter uns :)
        #print(thisdict["brand"])
        print(xmlData['OWNERSHIP'])


        #datei = open('/Export/textdatei.txt', 'a')
        #datei.write("\r\n" + (str(subchild.attrib)))
        #atei.close()
Ich würde mich freuen, wenn mir jemand helfen kann zu verstehen, was ich aktuell nicht verstehe :)
Sirius3
User
Beiträge: 18279
Registriert: Sonntag 21. Oktober 2012, 17:20

Es existiert offensichtlich kein Attribut mit dem Namen OWNERSHIP.
Wie sieht das XML aus, und was möchtest Du daraus extrahieren, und wie soll die Weiterverarbeitung aussehen?
TheUnreal
User
Beiträge: 4
Registriert: Montag 7. März 2022, 11:53

Moin Sirius,
und danke für die Hilfestellung. Ich zeige erstmal nur Ausschnitte, da die XML von einem Kunden kommt. Ich weiß ehrlich gesagt nicht, wie der das findet, wenn er es findet^^

Code: Alles auswählen

<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<repair_order>
<HEADER_INFORMATION>
<DETAIL TRANS_ID=""/>
<DETAIL SAP_KEY=""/>
</HEADER_INFORMATION>
<DEVICE_INFORMATION>
<DETAIL EAN=""/>
<DETAIL OWNERSHIP="CUSTOMER"/>
</DEVICE_INFORMATION>
.....
usw.
</repair_order>
Ich möchte die Values der Detail-Keys als String in der Datenbank ablegen, damit ich einen Forecast der anstehenden Reparatureinsendungen bekomme und die Aufträge im System vorhalten kann.

Gruß Sascha
Sirius3
User
Beiträge: 18279
Registriert: Sonntag 21. Oktober 2012, 17:20

Die Information, die Du möchtest, steckt in einem DETAIL-Tag, das innerhalb eines DEVICE_INFORMATION-Tags liegt.

Code: Alles auswählen

root = tree.getroot()
device_information = root.find('DEVICE_INFORMATION')
for detail in device_information.findall('DETAIL'):
    if "OWNERSHIP" in detail.attrib:
        print(detail.attrib['OWNERSHIP'])
TheUnreal
User
Beiträge: 4
Registriert: Montag 7. März 2022, 11:53

Vielen Dank für die Lösung, es gab den Schubs in die richtige Richtung.

Da ich im Grunde am Ende des Tages nicht wegen jeder Änderung in der XML von Werkstattseite an den Code ran möchte werde ich ein Array mit den notwendigen Keys füllen und mir darüber die Werte zu den benötigten Keys ziehen und mittels Funktion in die Datenbank schreiben.
In meiner Vorstellung ist es dann egal, falls neue Felder in der XML zugefügt werden - Array anpassen und gut ist. Ausserdem kann ich so unterschiedliche files einlesen und nur mit dem Array steuern, wie ich die weiterschieben will. Falls es nicht angekommen ist : Nochmal Danke :)

Code: Alles auswählen


for child in root:
    for subchild in child:

        tmp_key = subchild.keys()
        tmp_key = tmp_key[0]
        tmp_val = subchild.get(tmp_key)
        print(tmp_key + " = " + tmp_val)
        
Sirius3
User
Beiträge: 18279
Registriert: Sonntag 21. Oktober 2012, 17:20

Das ist keine gute Idee. XML-Strukturen sollten fix sein, da wild irgendwo Werte zusammenzusuchen führt dazu, dass bei Dateiänderungen niemand etwas mitbekommt und eventuell die Werte aus dem falschen Element gelesen werden.
Benutze `find` oder `findall` um die Daten aus der Struktur rauszulesen, wie sie definiert ist.

Zum Code:
was sollen die `tmp_`-Präfixe? Alle Variablen sind irgendwie temporär. Das hinzuschreiben hat keinen Informationsgehalt, stört also nur.
Keys `key´ zu nennen, ist sehr verwirrend. Auf die Attribute greift man über .attrib zu. Was das erste Attribut ist, ist mehr oder weniger zufällig. Warum zeigst Du nur das an?
TheUnreal
User
Beiträge: 4
Registriert: Montag 7. März 2022, 11:53

Zum Code :
Ist noch Spielcode, aber ich merke es mir. Key und Val weil es die Attribute der XML Knoten sind, also Key "OWNERSHIP" und Val wäre "CUSTOMER" - für mich war es eingängig^^.

̶z̶̶u̶̶m̶̶ ̶̶n̶̶u̶̶t̶̶z̶̶e̶̶n̶̶ ̶̶d̶̶e̶̶r̶̶ ̶̶x̶̶m̶̶l̶̶ ̶
̶v̶̶e̶̶r̶̶s̶̶t̶̶e̶̶h̶̶e̶̶ ̶̶i̶̶c̶̶h̶̶ ̶̶l̶̶e̶̶i̶̶d̶̶e̶̶r̶̶ ̶̶n̶̶o̶̶c̶̶h̶̶ ̶̶n̶̶i̶̶c̶̶h̶̶t̶̶ ̶̶s̶̶o̶̶ ̶̶g̶̶a̶̶n̶̶z̶̶,̶̶ ̶̶w̶̶o̶̶ ̶̶d̶̶e̶̶r̶̶ ̶̶v̶̶o̶̶r̶̶t̶̶e̶̶i̶̶l̶̶ ̶̶l̶̶i̶̶e̶̶g̶̶t̶̶,̶̶ ̶̶f̶̶i̶̶n̶̶d̶̶a̶̶l̶̶l̶̶ ̶̶z̶̶u̶̶ ̶̶n̶̶u̶̶t̶̶z̶̶e̶̶n̶̶.̶

̶i̶̶c̶̶h̶̶ ̶̶l̶̶e̶̶s̶̶e̶̶ ̶̶i̶̶n̶̶ ̶̶m̶̶e̶̶i̶̶n̶̶e̶̶m̶̶ ̶̶c̶̶o̶̶d̶̶e̶̶ ̶̶u̶̶n̶̶a̶̶b̶̶h̶̶ä̶̶n̶̶g̶̶i̶̶g̶̶ ̶̶d̶̶e̶̶r̶̶ ̶̶k̶̶n̶̶o̶̶t̶̶e̶̶n̶̶ ̶̶a̶̶l̶̶l̶̶e̶̶ ̶̶e̶̶l̶̶e̶̶m̶̶e̶̶n̶̶t̶̶e̶̶ ̶-̶ ̶̶d̶̶e̶̶n̶̶n̶̶ ̶̶i̶̶c̶̶h̶̶ ̶̶w̶̶e̶̶i̶̶ß̶̶,̶̶ ̶̶i̶̶n̶̶ ̶̶j̶̶e̶̶d̶̶e̶̶m̶̶ ̶̶k̶̶n̶̶o̶̶t̶̶e̶̶n̶̶ ̶̶s̶̶i̶̶n̶̶d̶̶ ̶̶d̶̶a̶̶t̶̶e̶̶n̶̶ ̶(̶s̶̶t̶̶r̶̶i̶̶n̶̶g̶̶s̶)̶ ̶̶z̶̶u̶̶ ̶̶e̶̶i̶̶n̶̶e̶̶m̶̶ ̶̶w̶̶e̶̶r̶̶k̶̶s̶̶t̶̶a̶̶t̶̶t̶̶a̶̶u̶̶f̶̶t̶̶r̶̶a̶̶g̶̶ ̶̶i̶̶n̶̶ ̶̶d̶̶e̶̶n̶̶ ̶̶e̶̶l̶̶e̶̶m̶̶e̶̶n̶̶t̶̶e̶̶n̶̶.̶
̶d̶̶i̶̶e̶̶s̶̶e̶̶ ̶̶d̶̶a̶̶t̶̶e̶̶n̶̶ ̶̶m̶̶ö̶̶c̶̶h̶̶t̶̶e̶̶ ̶̶i̶̶c̶̶h̶̶ ̶̶g̶̶e̶̶r̶̶n̶̶e̶̶ ̶̶e̶̶x̶̶t̶̶r̶̶a̶̶h̶̶i̶̶e̶̶r̶̶e̶̶n̶̶ ̶̶u̶̶n̶̶d̶̶ ̶̶i̶̶n̶̶ ̶̶e̶̶i̶̶n̶̶e̶̶ ̶̶t̶̶a̶̶b̶̶e̶̶l̶̶l̶̶e̶̶ ̶̶a̶̶n̶̶ ̶̶d̶̶i̶̶e̶̶ ̶̶e̶̶n̶̶t̶̶s̶̶p̶̶r̶̶e̶̶c̶̶h̶̶e̶̶n̶̶d̶̶e̶̶ ̶̶s̶̶t̶̶e̶̶l̶̶l̶̶e̶̶ ̶̶f̶̶ü̶̶g̶̶e̶̶n̶̶.̶̶ ̶̶d̶̶a̶̶z̶̶u̶̶ ̶̶n̶̶e̶̶h̶̶m̶̶e̶̶ ̶̶i̶̶c̶̶h̶̶ ̶̶m̶̶i̶̶r̶̶ ̶̶a̶̶l̶̶s̶̶o̶̶ ̶̶d̶̶e̶̶n̶̶ ̶̶k̶̶e̶̶y̶̶ ̶("̶o̶̶w̶̶n̶̶e̶̶r̶̶s̶̶h̶̶i̶̶p̶")̶,̶̶ ̶̶d̶̶e̶̶n̶̶ ̶̶i̶̶c̶̶h̶̶ ̶̶m̶̶i̶̶r̶̶ ̶̶a̶̶u̶̶s̶̶d̶̶e̶̶m̶̶ ̶̶e̶̶l̶̶e̶̶m̶̶e̶̶n̶̶t̶̶ ̶̶h̶̶o̶̶l̶̶e̶̶ ̶̶i̶̶n̶̶ ̶̶d̶̶e̶̶m̶̶ ̶̶i̶̶c̶̶h̶̶ ̶̶m̶̶i̶̶c̶̶h̶̶ ̶̶g̶̶r̶̶a̶̶d̶̶ ̶̶b̶̶e̶̶f̶̶i̶̶n̶̶d̶̶e̶̶ ̶̶u̶̶n̶̶d̶


Okay - ich lass es mal stehen - ich glaube beim Tippen meiner Frage hab ich die Antwort gefunden.(Und nach dem Absenden sogar in deiner Antwort...:() Ich habe an dieser Stelle Glück, dass das Attribut detail.keys nur eine Position hat, kommt einer hinzu, wäre die Position im Array ungenau und ich erhalte ein falsches Ergebnis während findall mir den Wert des per String gesuchten Keys zurückgibt?
Benutzeravatar
__blackjack__
User
Beiträge: 14078
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@TheUnreal: Ich glaube der Hinweis von Sirius3 war zu subtil: `key` ist als Name *Einzahl*, Du bindest da aber *mehrere* Schlüssel an den Namen, was dann `keys` heissen müsste.

Es ist auch etwas umständlich erst die/den Schlüssel zu ermitteln um dann über den auf den Wert zuzugreifen, weil man sich auch gleich die Schlüssel/Wert-Paare geben lassen kann:

Code: Alles auswählen

    for child in root:
        for subchild in child:
            for name, value in subchild.items():
                print(f"{name} = {value}")
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Antworten