Wie nicht benötigte XML-Daten löschen und bereinigt schreiben?

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
Hawky
User
Beiträge: 3
Registriert: Mittwoch 14. April 2021, 17:41

Mittwoch 14. April 2021, 18:22

Hallo zusammen,
ich bin relativ neu in Python , werde aber ab jetzt wohl öfter vorbeischauen :D
Ich darf im Praktikum ein Projekt mit XML-Dateien bearbeiten. Leider erhalte ich ein fehlerhaftes Ergebnis bei meinem Versuch...
Hier ein eigenes XML-Beispiel:

Code: Alles auswählen

<teilnehmer>

	<daten>
		<name>abc</name>
		<code>A111</code>
		<gruppe>1</gruppe>
	</daten>
	
	<daten>
		<name>efg</name>
		<code>A222</code>
		<gruppe>2</gruppe>
	</daten>
	
	<daten>
		<name>hij</name>
		<code>A333</code>
		<gruppe>3</gruppe>
	</daten>
	
</teilnehmer>
Ich habe Codes erhalten und würde gerne die Datensätze filtern. Daten die die gewünschten Codes besitzen werden behalten, der Rest wird gelöscht.
A111 und A222 sind gesucht und bleiben bestehen. A333 ist unwichtig und somit wird der komplette Datensatz gelöscht, also auch <name>,<gruppe> und anschließend werden die verbliebenen Daten in eine neue Datei geschrieben.
Ich habe es wie folgt probiert:

Code: Alles auswählen

import xml.etree.ElementTree as ET

xmlfile = "teilnehmer.xml"

tree = ET.parse(xmlfile)
root = tree.getroot()

for daten in root.findall('daten'):

    code = str(daten.find('code').text)
    if code != ("A111","A222"):

     root.remove(daten)

   
tree.write('teilnehmerneu.xml')

Die Datei teilnehmerneu.xml ist leider komplett leer nach dem Vorgang. Hier steht nur <teilnehmer> </teilnehmer>.

Das Ergebnis sollte aber sein:

Code: Alles auswählen

<teilnehmer>

	<daten>
		<name>abc</name>
		<code>A111</code>
		<gruppe>1</gruppe>
	</daten>
	
	<daten>
		<name>efg</name>
		<code>A222</code>
		<gruppe>2</gruppe>
	</daten>
	
</teilnehmer>
Ich bin mir nicht sicher, ob ich einen Fehler bei der if-Bedingung habe oder bereits bei der for-Schleife.

Vielleicht kann mir hier ja jemand weiterhelfen.
Danke!

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

Donnerstag 15. April 2021, 08:21

`daten.find('code').text` ist schon ein String, das nochmal in einen String zu verwandeln, ist unsinnig. Kürzer ist findtext.
`code` ist dann ein String und kann niemals gleich einem Tuple sein. Was Du suchst ist der in-Operator.

Ich würde nicht direkt auf der XML-Struktur arbeiten, sondern erst die komplette Datei in eine für das Programm sinnvolle Struktur packen (Liste), dann eine neue Liste mit den gefilterten Werten erzeugen und diese dann wieder als XML serialisieren.

Also für den Anfang:

Code: Alles auswählen

from collections import namedtuple
import xml.etree.ElementTree as et

Teilnehmer = namedtuple("Teilnehmer", "name,code,gruppe")

def deserialize(filename):
    tree = et.parse(filename)
    return [
        Teilnehmer(
            daten.findtext('name'),
            daten.findtext('code'),
            daten.findtext('gruppe'),
        )
        for daten in tree.findall('daten')
    ]
Hawky
User
Beiträge: 3
Registriert: Mittwoch 14. April 2021, 17:41

Donnerstag 15. April 2021, 18:07

Danke, mit "not in" konnte ich diese im XML filtern.

Ich versuche es mal mit dem von dir beschriebenen Code umzusetzen.
Hawky
User
Beiträge: 3
Registriert: Mittwoch 14. April 2021, 17:41

Donnerstag 15. April 2021, 19:02

Wäre es denn möglich einen Platzhalter einzusetzen sodass nur Teile des Codes benötigt werden?

Code: Alles auswählen

code = daten.findtext('code')
   if code not in ("A11*","A22*"):
Hier die * am Ende der gesuchten Codes, sodass A11 und A22 enthalten sein müssen. Es kann also auch das Ergebnis A11AA oder A22-1 herauskommen.
__deets__
User
Beiträge: 9685
Registriert: Mittwoch 14. Oktober 2015, 14:29

Donnerstag 15. April 2021, 22:31

Sowas geht mit fnmatch, aber dann musst du den in-Operator ersetzen durch eine Schleife. Ungetestet etwa sowas

Code: Alles auswählen

if not all(fnmatch.fnmatch(code, pattern) for pattern in (“A*”, “B*”)):
"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!!"
Benutzeravatar
__blackjack__
User
Beiträge: 8573
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Donnerstag 15. April 2021, 23:07

Ich würde da lieber das `re`-Modul verwenden, oder zumindest `fnmatchcase()` damit sich das unter Windows nicht anders verhält als unter Linux beispielsweise.
“Dawn, n.: The time when men of reason go to bed.” — Ambrose Bierce, “The Devil's Dictionary”
Sirius3
User
Beiträge: 14428
Registriert: Sonntag 21. Oktober 2012, 17:20

Freitag 16. April 2021, 06:31

In diesem Fall reicht ein ganz einfaches startswith:

Code: Alles auswählen

if not code.startswith(("A11", "A22")):
Antworten