XML Datei analysieren

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
guhamail
User
Beiträge: 22
Registriert: Samstag 19. Februar 2022, 13:34
Wohnort: Brandenburg

Hallo,

gegeben sei die folgende XML Datei:

Code: Alles auswählen

<?xml version="1.0" encoding="UTF-8"?>

<DataSet>
	<Version>2024</Version>
	<DataSupplier>
		<Name>FirmaXY</Name>
		<Location>LocationXY</Location>
		<Comment>Stand_30.09.2023</Comment>
	</DataSupplier>
	<Media>
		<Name>Datenträger</Name>
		<Table>
		  <URL>programminfo.csv</URL>
		  <Name>Programminfo</Name>
		  <Description>Informationen zum Softwareprogramm</Description>
		  <DecimalSymbol>,</DecimalSymbol>
		  <DigitGroupingSymbol>.</DigitGroupingSymbol>
		  <VariableLength>
		    <VariableColumn>
			   <Name>Softwarehersteller</Name>
			   <Description>Softwarehersteller</Description>
			   <AlphaNumeric/>
			   <MaxLength>60</MaxLength>
		    </VariableColumn>
		    <VariableColumn>
		       <Name>Softwarebezeichnung</Name>
		       <Description>Name der Software</Description>
		       <AlphaNumeric/>
		       <MaxLength>60</MaxLength>
		    </VariableColumn>
		    <VariableColumn>
		       <Name>Version</Name>
		       <Description>Versionsnummer</Description>
		       <AlphaNumeric/>
		       <MaxLength>60</MaxLength>
		    </VariableColumn>
		    <VariableColumn>
		       <Name>Branche</Name>
		       <Description>Anwendungsgebiet</Description>
		       <AlphaNumeric/>
		       <MaxLength>60</MaxLength>
		    </VariableColumn>
		    <VariableColumn>
		       <Name>Anschrift</Name>
		       <Description>Anschrift Hersteller</Description>
		       <AlphaNumeric/>
		       <MaxLength>60</MaxLength>
		    </VariableColumn>
		    <VariableColumn>
		       <Name>Ort</Name>
		       <Description>Ort Hersteller</Description>
		       <AlphaNumeric/>
		       <MaxLength>60</MaxLength>
		    </VariableColumn>
		  </VariableLength>
		</Table>
		<Table>
			<URL>stammdaten.csv</URL>
			<Name>Kundenstammdaten</Name>
			<Description>Angaben zum Kunde</Description>
			<DecimalSymbol>,</DecimalSymbol>
			<DigitGroupingSymbol>.</DigitGroupingSymbol>
			<VariableLength>
			  <VariableColumn>
				   <Name>KU_NR</Name>
				   <Description>Kundennummer</Description>
                   		   <AlphaNumeric/>
				   <MaxLength>14</MaxLength>
				</VariableColumn>
				<VariableColumn>
				   <Name>KU_Name</Name>
				   <Description>Name des Kunden</Description>
                  		  <AlphaNumeric/>
				   <MaxLength>40</MaxLength>
				</VariableColumn>
				<VariableColumn>
				  <Name>KU_Strasse_Nr</Name>
				  <Description>Straße und Hausnummer des Kunden</Description>
				  <AlphaNumeric/>
				  <MaxLength>40</MaxLength>
				</VariableColumn>
				<VariableColumn>
				  <Name>KU_Plz</Name>
				  <Description>PLZ des Kunden</Description>
				  <AlphaNumeric/>
				  <MaxLength>40</MaxLength>
				</VariableColumn>
			</VariableLength>
		</Table>
		<Table>
		  <URL>lieferantenstammdaten.csv</URL>
		  <Name>Lieferantenstammdaten</Name>
		  <Description>Angaben zum Lieferanten</Description>
		  <DecimalSymbol>,</DecimalSymbol>
		  <DigitGroupingSymbol>.</DigitGroupingSymbol>
		  <VariableLength> 
		    <VariableColumn>
		      <Name>Li_Jahr</Name>
		      <Description>Lieferjahr</Description>
		      <Numeric/>
		    </VariableColumn>
		    <VariableColumn>
		      <Name>Li_Mon</Name>
		      <Description>Liefermonat</Description>
		      <Numeric/>
		    </VariableColumn>
		    <VariableColumn>
		      <Name>Li_Zahl</Name>
		      <Description>Lieferzähler</Description>
		      <Numeric/>
		    </VariableColumn>
		    <VariableColumn>
		      <Name>Li_Nr</Name>
		      <Description>Liefernummer</Description>
		      <AlphaNumeric/>
		      <MaxLength>40</MaxLength>
		    </VariableColumn>
		    <VariableColumn>
		      <Name>ID_Nr</Name>
		      <Description>Identifikationsnummer</Description>
		      <AlphaNumeric/>
		      <MaxLength>11</MaxLength>
		    </VariableColumn>
		  </VariableLength>
		</Table>
	...
	</Media>
</DataSet>

Ich möchte den Inhalt der XML analysieren und mit einer Standardvorgabe vergleichen. Speziell interessieren mich erstmal die Tags <name> , <MaxLength>, <numeric> und <AlphaNumeic>.

Als Schwierigkeit kommt hinzu, dass auf dem System, wo das Skript laufen soll, das Modul pandas nur in der Version 0.20 verfügbar ist. Die Methode read_xml() steht also nicht zur Verfügung. Die installation weiterer Module ist auf dem System nicht möglich.

Ich stehe an dem Punkt, dass ich die XML in eine Liste eingelesen habe.

Code: Alles auswählen

datei = open("index.xml").readlines()
datei = [l.strip() for l in datei]
Wie extrahiere ich jetzt alle <table> Abschnitte aus der Liste?
Benutzeravatar
__blackjack__
User
Beiträge: 14235
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@guhamail: XML ist kein unstrukturierter Text, da sind Zeilen keine sinnvolle Einheit das zu verarbeiten. Dafür nimmt man einen XML-Parser. Beispielsweise `xml.etree.ElementTree` aus der Standardbibliothek.
“Ich bin für die Todesstrafe. Wer schreckliche Dinge getan hat, muss eine angemessene Strafe bekommen. So lernt er seine Lektion für das nächste Mal.” — Britney Spears, Interview in der französischen Zeitung Libération, 2. April 2002
Benutzeravatar
__blackjack__
User
Beiträge: 14235
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Mal als Ansatz:

Code: Alles auswählen

#!/usr/bin/env python3
from enum import Enum
from xml.etree import ElementTree

from attrs import field, frozen


class ColumnType(Enum):
    ALPHANUMERIC = "AlphaNumeric"
    NUMERIC = "Numeric"


@frozen
class Column:
    name = field()
    type = field()
    max_length = field(default=None)

    @classmethod
    def from_xml_element(cls, element):
        name = element.findtext("Name")
        for column_type in ColumnType:
            if element.find(column_type.value) is not None:
                break
        else:
            raise ValueError(
                f"{element.tag} element with name {name!r} that has no"
                f" ColumnType"
            )
        max_length_text = element.findtext("MaxLength")
        max_length = int(max_length_text) if max_length_text else None
        return cls(name, column_type, max_length)


@frozen
class Table:
    url = field()
    columns = field(factory=list)

    @classmethod
    def from_xml_element(cls, element):
        return cls(
            element.findtext("URL"),
            list(
                map(
                    Column.from_xml_element,
                    element.findall("VariableLength/VariableColumn"),
                )
            ),
        )


def parse_tables(filename):
    return map(
        Table.from_xml_element,
        ElementTree.parse(filename).findall("Media/Table"),
    )


def main():
    for table in parse_tables("test.xml"):
        print(table.url)
        for column in table.columns:
            print(" ", column)


if __name__ == "__main__":
    main()
Ausgabe für die Testdaten aus dem ersten Beitrag:

Code: Alles auswählen

programminfo.csv
  Column(name='Softwarehersteller', type=<ColumnType.ALPHANUMERIC: 'AlphaNumeric'>, max_length=60)
  Column(name='Softwarebezeichnung', type=<ColumnType.ALPHANUMERIC: 'AlphaNumeric'>, max_length=60)
  Column(name='Version', type=<ColumnType.ALPHANUMERIC: 'AlphaNumeric'>, max_length=60)
  Column(name='Branche', type=<ColumnType.ALPHANUMERIC: 'AlphaNumeric'>, max_length=60)
  Column(name='Anschrift', type=<ColumnType.ALPHANUMERIC: 'AlphaNumeric'>, max_length=60)
  Column(name='Ort', type=<ColumnType.ALPHANUMERIC: 'AlphaNumeric'>, max_length=60)
stammdaten.csv
  Column(name='KU_NR', type=<ColumnType.ALPHANUMERIC: 'AlphaNumeric'>, max_length=14)
  Column(name='KU_Name', type=<ColumnType.ALPHANUMERIC: 'AlphaNumeric'>, max_length=40)
  Column(name='KU_Strasse_Nr', type=<ColumnType.ALPHANUMERIC: 'AlphaNumeric'>, max_length=40)
  Column(name='KU_Plz', type=<ColumnType.ALPHANUMERIC: 'AlphaNumeric'>, max_length=40)
lieferantenstammdaten.csv
  Column(name='Li_Jahr', type=<ColumnType.NUMERIC: 'Numeric'>, max_length=None)
  Column(name='Li_Mon', type=<ColumnType.NUMERIC: 'Numeric'>, max_length=None)
  Column(name='Li_Zahl', type=<ColumnType.NUMERIC: 'Numeric'>, max_length=None)
  Column(name='Li_Nr', type=<ColumnType.ALPHANUMERIC: 'AlphaNumeric'>, max_length=40)
  Column(name='ID_Nr', type=<ColumnType.ALPHANUMERIC: 'AlphaNumeric'>, max_length=11)
“Ich bin für die Todesstrafe. Wer schreckliche Dinge getan hat, muss eine angemessene Strafe bekommen. So lernt er seine Lektion für das nächste Mal.” — Britney Spears, Interview in der französischen Zeitung Libération, 2. April 2002
Antworten