XML-Datei auslesen und in csv-Format umwandeln

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
BlackJack

@Nobuddy: Es ist eine Klasse wenn es Daten und Funktionen die darauf operieren sinnvoll zu einem Objekt zusammenfasst. Also dann wenn es gegenüber Funktionen einen Vorteil bietet.

`namespace` ist ein bisschen Allgemein. Dem Leser stellt sich dann als nächstes die Frage welcher Namespace es ist. Der Sinn von Namespaces ist ja gerade das man mehrere davon haben kann.

Die Elemente vom Ergebnis von `read_xml()` sind Listen wo die einzelnen Elemente abhängig vom Index eine andere Bedeutung haben. Das heisst man muss wissen was welcher Index bedeutet und wenn man darauf zugreifen will braucht man magische Indexnummern. Das ist die Stelle wo man ein Wörterbuch oder ein `collections.namedtuple` verwenden würde, damit der Code lesbar und verständlich bleibt. Da die Daten am Ende in eine CSV-Datei gechrieben werden sollen, würde sich hier beispielsweise ein Wörterbuch anbieten und ein `csv.DictWriter` zum schreiben der Daten.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Nobuddy: das read_xml kann man ganz einfach als Funktion definieren, ohne irgendwelche Einschränkungen zu haben. Was soll eine Konstante der Datei sein? Inhalte von Dateien sind per Definition variabel. XML ist als Dateiformat sehr strikt. Jede kleinste Abweichung vom Erwarteten wird normalerweise als Fehler geahndet. Benutzinteraktion sollte nicht in einer Funktion erfolgen, die so generelle Sachen macht, wie eine Datei lesen. Das gehört auf einer höheren Ebene abgearbeitet. Fehler werden als Exceptions hochgemeldet.

Code: Alles auswählen

from collections import namedtuple
from lxml import etree
 
XmlFormatDescription = namedtuple("XmlFormatDescription", "namespace, start_path, details")
 
# Unterstützte XML-Formate
XML_DESCRIPTIONS = {
    '{http://www.bmecat.org/bmecat/1.2/bmecat_new_catalog}BMECAT': XmlFormatDescription(
        "{http://www.bmecat.org/bmecat/1.2/bmecat_new_catalog}",
        ["ARTICLE"],
        {
            "manufacturer": ['ARTICLE_DETAILS', 'MANUFACTURER_NAME'],
            "supplier_aid": ['SUPPLIER_AID'],
            "description": ['ARTICLE_DETAILS', 'DESCRIPTION_SHORT'],
            "ean": ['ARTICLE_DETAILS', 'EAN'],
        })
    '{http://www.bmecat.org/bmecat/2005fd}BMECAT': XmlFormatDescription(
        "{http://www.bmecat.org/bmecat/2005fd}",
        ["PRODUCT"],
        {
            "manufacturer": ['PRODUCT_DETAILS', 'MANUFACTURER_NAME'],
            "supplier_aid": ['SUPPLIER_AID'],
            "description": ['PRODUCT_DETAILS', 'DESCRIPTION_SHORT'],
            "ean": ['PRODUCT_DETAILS', 'EAN'],
        })
}

def generate_path(namespace, path):
    """
    Erstellt einen XML-Pfaden.
    """
    return '/'.join('{}{}'.format(namespace, t) for t in path)
     
def read_xml(filename, descriptions):
    """
    Lade XML-Datei in eine Liste mit Wörterbüchern.
    """
    root = etree.parse(self.filepath).getroot()
    description = descriptions[root.tag]
    
    start_path = generate_path(description.namespace, description.start_path)
    xml_paths = {key: generate_path(description.namespace, path) for key, path in description.details.items()}
    result = []
    for entry in root.findall(start_path):
        for key, path in xml_paths.items():
            result[key] = entry.findtext(path)
        return result
 
def main():
    filepath = '/home/whtb/Downloads/preisliste/BMEcat_514281.xml'
    data = read_xml(filepath, XML_DESCRIPTIONS)
    for row in data[:50]:
        print(row)
 
if __name__ == '__main__':
    main()
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo und Danke Euch beiden, für Eure Geduld und Hilfe! :wink:

Habe mir gestern bei BMECAD, die verschiedenen Schnittellenbeschreibungen angeschaut.
Mir ist jetzt klar geworden, dass ich von einem falschen Ausgangspunkt das Ganze betrachtet habe.
Was ich will, ist Produktdaten von Lieferanten in mein System einzuspielen. Da werden unterschiedlichste Datei-Formate angeboten, mit denen man sich oft intensiv auseinandersetzen muss, bevor man die Daten in das System einspielen kann.
BMECAD bietet eine Schnittstellenbeschreibung, diese ist eine Konstante für alle die dies für Ihren Produktkatalog verwenden.
Dies vereinfacht das Ganze, da man das Rad nicht jedes mal neu erfinden muss.

Jetzt ist mir auch klar geworden, was Ihr mir mit Euren Beiträgen klar machen wollt.
Sirius3, Dein letztes Code-Beispiel, hat mir das nochmals veranschaulicht, wie und wo die Prioritäten einzusetzen sind.

Ich werde das letzte Code-Beispiel von Sirius3 als Basis verwenden und die Schnittstellenbeschreibung von BMECAT zu studieren.

Bei weiteren Fragen zu diesem Thema melde ich mich wieder.

Grüße Nobuddy
Antworten