Kurs
Python XML Tutorial mit ElementTree: Leitfaden für Anfänger
Führe den Code aus diesem Tutorial online aus und bearbeite ihn
Code ausführenAls Datenwissenschaftler/in wirst du feststellen, dass das Verständnis von XML sowohl für das Web-Scraping als auch für die allgemeine Praxis des Parsens von strukturierten Dokumenten wichtig ist.
- Du lernst mehr über XML und bekommst eine Einführung in das Python-Paket
ElementTree
. - Dann erfährst du, wie du XML-Bäume untersuchen kannst, um die Daten, mit denen du arbeitest, mit Hilfe von
ElementTree
Funktionen, for-Schleifen und XPath-Ausdrücken besser zu verstehen. - Als Nächstes lernst du, wie du eine XML-Datei ändern kannst.
- Du wirst auch xpath-Ausdrücke verwenden, um XML-Dateien aufzufüllen.
Python von Grund auf lernen
Was ist XML?
XML steht für "Extensible Markup Language". Es wird hauptsächlich in Webseiten verwendet, wo die Daten eine bestimmte Struktur haben und vom XML-Framework dynamisch verstanden werden.
XML erzeugt eine baumartige Struktur, die leicht zu interpretieren ist und eine Hierarchie unterstützt. Wann immer eine Seite XML folgt, kann sie als XML-Dokument bezeichnet werden.
- XML-Dokumente haben Abschnitte, die Elemente genannt werden und durch einen Anfangs- und einen Endtag definiert sind. Ein Tag ist ein Markup-Konstrukt, das mit
<
beginnt und mit>
endet. Die Zeichen zwischen dem Start-Tag und dem End-Tag, sofern vorhanden, sind der Inhalt des Elements. Elemente können Markup enthalten, darunter auch andere Elemente, die als "Kindelemente" bezeichnet werden. - Das größte, oberste Element wird als Wurzel bezeichnet, die alle anderen Elemente enthält.
- Attribute sind Name-Wert-Paare, die sich innerhalb eines Start-Tags oder eines Leerelement-Tags befinden. Ein XML-Attribut kann nur einen einzigen Wert haben und jedes Attribut kann in jedem Element höchstens einmal vorkommen.
Um dies etwas besser zu verstehen, schau dir die folgende (gekürzte) XML-Datei an:
<?xml version="1.0"?>
<collection>
<genre category="Action">
<decade years="1980s">
<movie favorite="True" title="Indiana Jones: The raiders of the lost Ark">
<format multiple="No">DVD</format>
<year>1981</year>
<rating>PG</rating>
<description>
'Archaeologist and adventurer Indiana Jones
is hired by the U.S. government to find the Ark of the
Covenant before the Nazis.'
</description>
</movie>
<movie favorite="True" title="THE KARATE KID">
<format multiple="Yes">DVD,Online</format>
<year>1984</year>
<rating>PG</rating>
<description>None provided.</description>
</movie>
<movie favorite="False" title="Back 2 the Future">
<format multiple="False">Blu-ray</format>
<year>1985</year>
<rating>PG</rating>
<description>Marty McFly</description>
</movie>
</decade>
<decade years="1990s">
<movie favorite="False" title="X-Men">
<format multiple="Yes">dvd, digital</format>
<year>2000</year>
<rating>PG-13</rating>
<description>Two mutants come to a private academy for their kind whose resident superhero team must
oppose a terrorist organization with similar powers.</description>
</movie>
<movie favorite="True" title="Batman Returns">
<format multiple="No">VHS</format>
<year>1992</year>
<rating>PG13</rating>
<description>NA.</description>
</movie>
<movie favorite="False" title="Reservoir Dogs">
<format multiple="No">Online</format>
<year>1992</year>
<rating>R</rating>
<description>WhAtEvER I Want!!!?!</description>
</movie>
</decade>
</genre>
<genre category="Thriller">
<decade years="1970s">
<movie favorite="False" title="ALIEN">
<format multiple="Yes">DVD</format>
<year>1979</year>
<rating>R</rating>
<description>"""""""""</description>
</movie>
</decade>
<decade years="1980s">
<movie favorite="True" title="Ferris Bueller's Day Off">
<format multiple="No">DVD</format>
<year>1986</year>
<rating>PG13</rating>
<description>Funny movie about a funny guy</description>
</movie>
<movie favorite="FALSE" title="American Psycho">
<format multiple="No">blue-ray</format>
<year>2000</year>
<rating>Unrated</rating>
<description>psychopathic Bateman</description>
</movie>
</decade>
</genre>
Aus dem, was du oben gelesen hast, kannst du erkennen, dass
ist das einzige Wurzelelement: Es enthält alle anderen Elemente, wie
oder
, die die untergeordneten Elemente oder Unterelemente sind. Wie du sehen kannst, sind diese Elemente verschachtelt.
Beachte, dass diese untergeordneten Elemente auch als Eltern fungieren und ihre eigenen untergeordneten Elemente enthalten können, die dann "untergeordnete Elemente" genannt werden.
- Du wirst sehen, dass zum Beispiel das Element
eine Reihe von "Attributen" enthält, wie
favorite
title
, die noch mehr Informationen liefern!
Mit dieser kurzen Einführung in XML-Dateien im Kopf bist du bereit, mehr über ElementTree
zu erfahren!
Einführung in ElementTree
Die XML-Baumstruktur macht das Navigieren, Ändern und Entfernen programmtechnisch relativ einfach. Python hat eine eingebaute Bibliothek, ElementTree
, die Funktionen zum Lesen und Verarbeiten von XML-Dateien (und anderen ähnlich strukturierten Dateien) enthält.
Importiere zunächst ElementTree
. Es ist eine gängige Praxis, den Alias ET
zu verwenden:
import xml.etree.ElementTree as ET
Parsen von XML-Daten
Die mitgelieferte XML-Datei beschreibt eine einfache Sammlung von Filmen. Das einzige Problem ist, dass die Daten ein Chaos sind! Es gab viele verschiedene Kuratoren für diese Sammlung und jeder hat seine eigene Art, Daten in die Datei einzugeben. In diesem Lernprogramm geht es vor allem darum, die Datei mit Python zu lesen und zu verstehen und dann die Probleme zu beheben.
Zuerst musst du die Datei mit ElementTree
lesen.
tree = ET.parse('movies.xml')
root = tree.getroot()
Jetzt, wo du den Baum initialisiert hast, solltest du dir das XML ansehen und Werte ausdrucken, um zu verstehen, wie der Baum strukturiert ist.
Jeder Teil eines Baums (einschließlich der Wurzel) hat ein Tag, das das Element beschreibt. Wie du in der Einführung gesehen hast, können Elemente außerdem Attribute haben, also zusätzliche Beschreibungen, die vor allem für die wiederholte Verwendung von Tags verwendet werden. Attribute helfen auch bei der Validierung von Werten, die für dieses Tag eingegeben werden, was wiederum zum strukturierten Format einer XML-Datei beiträgt.
Du wirst später in diesem Tutorial sehen, dass Attribute ziemlich mächtig sein können, wenn sie in einer XML-Datei enthalten sind!
root.tag
'collection'
Auf der obersten Ebene siehst du, dass diese XML im collection
Tag verwurzelt ist.
root.attrib
{}
Die Wurzel hat also keine Attribute.
Für Schleifen
Mit einer einfachen "for"-Schleife kannst du ganz einfach über die Unterelemente (auch "Kinder" genannt) in der Wurzel iterieren.
for child in root:
print(child.tag, child.attrib)
genre {'category': 'Action'}
genre {'category': 'Thriller'}
genre {'category': 'Comedy'}
Jetzt weißt du, dass die Kinder der Wurzel collection
alle genre
sind. Um das Genre zu bezeichnen, verwendet die XML das Attribut category
. Es gibt Action-, Thriller- und Komödienfilme nach dem genre
Element.
Normalerweise ist es hilfreich, alle Elemente im gesamten Baum zu kennen. Eine nützliche Funktion dafür ist root.iter()
. Du kannst diese Funktion in eine "for"-Schleife einbauen und sie durchläuft den gesamten Baum.
[elem.tag for elem in root.iter()]
['collection',
'genre',
'decade',
'movie',
'format',
'year',
'rating',
'description',
'movie',
'format',
'year',
'rating',
'description',
'movie',
'format',
'year',
'rating',
'description',
'decade',
'movie',
'format',
'year',
'rating',
'description',
'movie',
'format',
'year',
'rating',
'description',
'movie',
'format',
'year',
'rating',
'description',
'genre',
'decade',
'movie',
'format',
'year',
'rating',
'description',
'decade',
'movie',
'format',
'year',
'rating',
'description',
'movie',
'format',
'year',
'rating',
'description',
'genre',
'decade',
'movie',
'format',
'year',
'rating',
'description',
'decade',
'movie',
'format',
'year',
'rating',
'description',
'movie',
'format',
'year',
'rating',
'description',
'decade',
'movie',
'format',
'year',
'rating',
'description',
'decade',
'movie',
'format',
'year',
'rating',
'description']
Dies gibt eine allgemeine Vorstellung davon, wie viele Elemente du hast, aber es zeigt nicht die Attribute oder Ebenen im Baum.
Es gibt eine hilfreiche Möglichkeit, das ganze Dokument zu sehen. Jedes Element hat eine .tostring()
Methode. Wenn du die Wurzel an die Methode .tostring()
übergibst, kannst du das gesamte Dokument zurückgeben. Innerhalb von ElementTree
(wir erinnern uns: ET
) nimmt .tostring()
eine etwas seltsame Form an.
Da ElementTree
eine leistungsstarke Bibliothek ist, die mehr als nur XML interpretieren kann. Du musst sowohl die Kodierung als auch die Dekodierung des Dokuments angeben, das du als Zeichenfolge anzeigst. Verwende für XMLs 'utf8'
- Das ist das typische Dokumentformat für XML.
print(ET.tostring(root, encoding='utf8').decode('utf8'))
<?xml version='1.0' encoding='utf8'?>
<collection>
<genre category="Action">
<decade years="1980s">
<movie favorite="True" title="Indiana Jones: The raiders of the lost Ark">
<format multiple="No">DVD</format>
<year>1981</year>
<rating>PG</rating>
<description>
'Archaeologist and adventurer Indiana Jones
is hired by the U.S. government to find the Ark of the
Covenant before the Nazis.'
</description>
</movie>
<movie favorite="True" title="THE KARATE KID">
<format multiple="Yes">DVD,Online</format>
<year>1984</year>
<rating>PG</rating>
<description>None provided.</description>
</movie>
<movie favorite="False" title="Back 2 the Future">
<format multiple="False">Blu-ray</format>
<year>1985</year>
<rating>PG</rating>
<description>Marty McFly</description>
</movie>
</decade>
<decade years="1990s">
<movie favorite="False" title="X-Men">
<format multiple="Yes">dvd, digital</format>
<year>2000</year>
<rating>PG-13</rating>
<description>Two mutants come to a private academy for their kind whose resident superhero team must
oppose a terrorist organization with similar powers.</description>
</movie>
<movie favorite="True" title="Batman Returns">
<format multiple="No">VHS</format>
<year>1992</year>
<rating>PG13</rating>
<description>NA.</description>
</movie>
<movie favorite="False" title="Reservoir Dogs">
<format multiple="No">Online</format>
<year>1992</year>
<rating>R</rating>
<description>WhAtEvER I Want!!!?!</description>
</movie>
</decade>
</genre>
<genre category="Thriller">
<decade years="1970s">
<movie favorite="False" title="ALIEN">
<format multiple="Yes">DVD</format>
<year>1979</year>
<rating>R</rating>
<description>"""""""""</description>
</movie>
</decade>
<decade years="1980s">
<movie favorite="True" title="Ferris Bueller's Day Off">
<format multiple="No">DVD</format>
<year>1986</year>
<rating>PG13</rating>
<description>Funny movie about a funny guy</description>
</movie>
<movie favorite="FALSE" title="American Psycho">
<format multiple="No">blue-ray</format>
<year>2000</year>
<rating>Unrated</rating>
<description>psychopathic Bateman</description>
</movie>
</decade>
</genre>
<genre category="Comedy">
<decade years="1960s">
<movie favorite="False" title="Batman: The Movie">
<format multiple="Yes">DVD,VHS</format>
<year>1966</year>
<rating>PG</rating>
<description>What a joke!</description>
</movie>
</decade>
<decade years="2010s">
<movie favorite="True" title="Easy A">
<format multiple="No">DVD</format>
<year>2010</year>
<rating>PG--13</rating>
<description>Emma Stone = Hester Prynne</description>
</movie>
<movie favorite="True" title="Dinner for SCHMUCKS">
<format multiple="Yes">DVD,digital,Netflix</format>
<year>2011</year>
<rating>Unrated</rating>
<description>Tim (Rudd) is a rising executive
who “succeeds” in finding the perfect guest,
IRS employee Barry (Carell), for his boss’ monthly event,
a so-called “dinner for idiots,” which offers certain
advantages to the exec who shows up with the biggest buffoon.
</description>
</movie>
</decade>
<decade years="1980s">
<movie favorite="False" title="Ghostbusters">
<format multiple="No">Online,VHS</format>
<year>1984</year>
<rating>PG</rating>
<description>Who ya gonna call?</description>
</movie>
</decade>
<decade years="1990s">
<movie favorite="True" title="Robin Hood: Prince of Thieves">
<format multiple="No">Blu_Ray</format>
<year>1991</year>
<rating>Unknown</rating>
<description>Robin Hood slaying</description>
</movie>
</decade>
</genre>
</collection>
Du kannst die Funktion iter()
erweitern, um bestimmte Elemente von Interesse zu finden. root.iter()
listet alle Unterelemente unter der Wurzel auf, die dem angegebenen Element entsprechen. Hier listest du alle Attribute des Elements movie
im Baum auf:
for movie in root.iter('movie'):
print(movie.attrib)
{'favorite': 'True', 'title': 'Indiana Jones: The raiders of the lost Ark'}
{'favorite': 'True', 'title': 'THE KARATE KID'}
{'favorite': 'False', 'title': 'Back 2 the Future'}
{'favorite': 'False', 'title': 'X-Men'}
{'favorite': 'True', 'title': 'Batman Returns'}
{'favorite': 'False', 'title': 'Reservoir Dogs'}
{'favorite': 'False', 'title': 'ALIEN'}
{'favorite': 'True', 'title': "Ferris Bueller's Day Off"}
{'favorite': 'FALSE', 'title': 'American Psycho'}
{'favorite': 'False', 'title': 'Batman: The Movie'}
{'favorite': 'True', 'title': 'Easy A'}
{'favorite': 'True', 'title': 'Dinner for SCHMUCKS'}
{'favorite': 'False', 'title': 'Ghostbusters'}
{'favorite': 'True', 'title': 'Robin Hood: Prince of Thieves'}
Du kannst bereits sehen, wie die movies
auf unterschiedliche Weise eingegeben wurden. Mach dir darüber erst einmal keine Gedanken. Du wirst später in diesem Lernprogramm die Möglichkeit haben, einen der Fehler zu beheben.
XPath-Ausdrücke
Oft haben Elemente keine Attribute, sondern nur einen Textinhalt. Mit dem Attribut .text
kannst du diesen Inhalt ausdrucken.
Drucke nun alle Beschreibungen der Filme aus.
for description in root.iter('description'):
print(description.text)
'Archaeologist and adventurer Indiana Jones
is hired by the U.S. government to find the Ark of the
Covenant before the Nazis.'
None provided.
Marty McFly
Two mutants come to a private academy for their kind whose resident superhero team must
oppose a terrorist organization with similar powers.
NA.
WhAtEvER I Want!!!?!
"""""""""
Funny movie about a funny guy
psychopathic Bateman
What a joke!
Emma Stone = Hester Prynne
Tim (Rudd) is a rising executive
who “succeeds” in finding the perfect guest,
IRS employee Barry (Carell), for his boss’ monthly event,
a so-called “dinner for idiots,” which offers certain
advantages to the exec who shows up with the biggest buffoon.
Who ya gonna call?
Robin Hood slaying
Das Ausdrucken der XML-Datei ist hilfreich, aber XPath ist eine Abfragesprache, mit der man schnell und einfach eine XML-Datei durchsuchen kann. XPath steht für XML Path Language und verwendet, wie der Name schon sagt, eine "pfadähnliche" Syntax, um Knoten in einem XML-Dokument zu identifizieren und zu navigieren.
Das Verständnis von XPath ist für das Scannen und Auffüllen von XMLs von entscheidender Bedeutung. ElementTree
hat eine .findall()
Funktion, die die unmittelbaren Kinder des referenzierten Elements durchläuft. Du kannst XPath-Ausdrücke verwenden, um nützlichere Suchen zu definieren.
Hier durchsuchst du den Baum nach Filmen, die im Jahr 1992 herauskamen:
for movie in root.findall("./genre/decade/movie/[year='1992']"):
print(movie.attrib)
{'favorite': 'True', 'title': 'Batman Returns'}
{'favorite': 'False', 'title': 'Reservoir Dogs'}
Die Funktion .findall()
beginnt immer bei dem angegebenen Element. Diese Art von Funktion ist extrem leistungsstark für das "Suchen und Ersetzen". Du kannst sogar nach Attributen suchen!
Jetzt druckst du nur die Filme aus, die in mehreren Formaten verfügbar sind (ein Attribut).
for movie in root.findall("./genre/decade/movie/format/[@multiple='Yes']"):
print(movie.attrib)
{'multiple': 'Yes'}
{'multiple': 'Yes'}
{'multiple': 'Yes'}
{'multiple': 'Yes'}
{'multiple': 'Yes'}
Überlege dir, warum die Druckanweisung in diesem Fall die "Ja"-Werte von multiple
zurückgibt. Denke darüber nach, wie die "for"-Schleife definiert ist. Könntest du diese Schleife so umschreiben, dass sie stattdessen die Filmtitel ausgibt? Probiere es unten aus:
Tipp: Verwende '...'
innerhalb von XPath, um das übergeordnete Element des aktuellen Elements zurückzugeben.
for movie in root.findall("./genre/decade/movie/format[@multiple='Yes']..."):
print(movie.attrib)
{'favorite': 'True', 'title': 'THE KARATE KID'}
{'favorite': 'False', 'title': 'X-Men'}
{'favorite': 'False', 'title': 'ALIEN'}
{'favorite': 'False', 'title': 'Batman: The Movie'}
{'favorite': 'True', 'title': 'Dinner for SCHMUCKS'}
Ändern einer XML-Datei
Früher waren die Filmtitel ein absolutes Chaos. Drucke sie jetzt noch einmal aus:
for movie in root.iter('movie'):
print(movie.attrib)
{'favorite': 'True', 'title': 'Indiana Jones: The raiders of the lost Ark'}
{'favorite': 'True', 'title': 'THE KARATE KID'}
{'favorite': 'False', 'title': 'Back 2 the Future'}
{'favorite': 'False', 'title': 'X-Men'}
{'favorite': 'True', 'title': 'Batman Returns'}
{'favorite': 'False', 'title': 'Reservoir Dogs'}
{'favorite': 'False', 'title': 'ALIEN'}
{'favorite': 'True', 'title': "Ferris Bueller's Day Off"}
{'favorite': 'FALSE', 'title': 'American Psycho'}
{'favorite': 'False', 'title': 'Batman: The Movie'}
{'favorite': 'True', 'title': 'Easy A'}
{'favorite': 'True', 'title': 'Dinner for SCHMUCKS'}
{'favorite': 'False', 'title': 'Ghostbusters'}
{'favorite': 'True', 'title': 'Robin Hood: Prince of Thieves'}
Repariere die "2" in Zurück in die Zukunft. Das sollte ein Problem beim Suchen und Ersetzen sein. Schreibe einen Code, um den Titel "Back 2 the Future" zu finden und ihn als Variable zu speichern:
b2tf = root.find("./genre/decade/movie[@title='Back 2 the Future']")
print(b2tf)
<Element 'movie' at 0x10ce00ef8>
Beachte, dass die Methode .find()
ein Element des Baums zurückgibt. Meistens ist es sinnvoller, den Inhalt eines Elements zu bearbeiten.
Ändere das title
Attribut der Back 2 the Future Elementvariable so, dass es "Back to the Future" lautet. Drucke dann die Attribute deiner Variablen aus, um deine Änderung zu sehen. Das kannst du ganz einfach tun, indem du auf das Attribut eines Elements zugreifst und ihm dann einen neuen Wert zuweist:
b2tf.attrib["title"] = "Back to the Future"
print(b2tf.attrib)
{'favorite': 'False', 'title': 'Back to the Future'}
Schreibe deine Änderungen in die XML-Datei zurück, damit sie dauerhaft im Dokument verankert sind. Drucke deine Filmattribute noch einmal aus, um sicherzustellen, dass deine Änderungen funktioniert haben. Verwende dazu die Methode .write()
:
tree.write("movies.xml")
tree = ET.parse('movies.xml')
root = tree.getroot()
for movie in root.iter('movie'):
print(movie.attrib)
{'favorite': 'True', 'title': 'Indiana Jones: The raiders of the lost Ark'}
{'favorite': 'True', 'title': 'THE KARATE KID'}
{'favorite': 'False', 'title': 'Back to the Future'}
{'favorite': 'False', 'title': 'X-Men'}
{'favorite': 'True', 'title': 'Batman Returns'}
{'favorite': 'False', 'title': 'Reservoir Dogs'}
{'favorite': 'False', 'title': 'ALIEN'}
{'favorite': 'True', 'title': "Ferris Bueller's Day Off"}
{'favorite': 'FALSE', 'title': 'American Psycho'}
{'favorite': 'False', 'title': 'Batman: The Movie'}
{'favorite': 'True', 'title': 'Easy A'}
{'favorite': 'True', 'title': 'Dinner for SCHMUCKS'}
{'favorite': 'False', 'title': 'Ghostbusters'}
{'favorite': 'True', 'title': 'Robin Hood: Prince of Thieves'}
Attribute fixieren
Das Attribut multiple
ist an einigen Stellen falsch. Verwende ElementTree
, um den Bezeichner festzulegen, je nachdem, in wie vielen Formaten der Film vorliegt. Drucke zunächst das Attribut format
und den Text aus, um zu sehen, welche Teile korrigiert werden müssen.
for form in root.findall("./genre/decade/movie/format"):
print(form.attrib, form.text)
{'multiple': 'No'} DVD
{'multiple': 'Yes'} DVD,Online
{'multiple': 'False'} Blu-ray
{'multiple': 'Yes'} dvd, digital
{'multiple': 'No'} VHS
{'multiple': 'No'} Online
{'multiple': 'Yes'} DVD
{'multiple': 'No'} DVD
{'multiple': 'No'} blue-ray
{'multiple': 'Yes'} DVD,VHS
{'multiple': 'No'} DVD
{'multiple': 'Yes'} DVD,digital,Netflix
{'multiple': 'No'} Online,VHS
{'multiple': 'No'} Blu_Ray
Es gibt noch einiges zu tun an diesem Tag.
Du kannst Regex verwenden, um Kommas zu finden - das sagt dir, ob das Attribut multiple
"Ja" oder "Nein" sein soll. Das Hinzufügen und Ändern von Attributen kann ganz einfach mit der Methode .set()
erfolgen.
Hinweis: re
ist der Standard-Regex-Interpreter für Python. Wenn du mehr über reguläre Ausdrücke wissen willst, schau dir dieses Tutorial an.
import re
for form in root.findall("./genre/decade/movie/format"):
# Search for the commas in the format text
match = re.search(',',form.text)
if match:
form.set('multiple','Yes')
else:
form.set('multiple','No')
# Write out the tree to the file again
tree.write("movies.xml")
tree = ET.parse('movies.xml')
root = tree.getroot()
for form in root.findall("./genre/decade/movie/format"):
print(form.attrib, form.text)
{'multiple': 'No'} DVD
{'multiple': 'Yes'} DVD,Online
{'multiple': 'No'} Blu-ray
{'multiple': 'Yes'} dvd, digital
{'multiple': 'No'} VHS
{'multiple': 'No'} Online
{'multiple': 'No'} DVD
{'multiple': 'No'} DVD
{'multiple': 'No'} blue-ray
{'multiple': 'Yes'} DVD,VHS
{'multiple': 'No'} DVD
{'multiple': 'Yes'} DVD,digital,Netflix
{'multiple': 'Yes'} Online,VHS
{'multiple': 'No'} Blu_Ray
Bewegende Elemente
Einige der Daten wurden dem falschen Jahrzehnt zugeordnet. Nutze das, was du über XML und ElementTree
gelernt hast, um die Fehler in den Dekadendaten zu finden und zu beheben.
Es ist sinnvoll, sowohl die decade
Tags als auch die year
Tags im Dokument auszudrucken.
for decade in root.findall("./genre/decade"):
print(decade.attrib)
for year in decade.findall("./movie/year"):
print(year.text, '\n')
{'years': '1980s'}
1981
1984
1985
{'years': '1990s'}
2000
1992
1992
{'years': '1970s'}
1979
{'years': '1980s'}
1986
2000
{'years': '1960s'}
1966
{'years': '2010s'}
2010
2011
{'years': '1980s'}
1984
{'years': '1990s'}
1991
Die beiden Jahre, die im falschen Jahrzehnt liegen, sind die Filme aus den 2000er Jahren. Finde heraus, welche Filme das sind, indem du einen XPath-Ausdruck verwendest.
for movie in root.findall("./genre/decade/movie/[year='2000']"):
print(movie.attrib)
{'favorite': 'False', 'title': 'X-Men'}
{'favorite': 'FALSE', 'title': 'American Psycho'}
Du musst ein neues Jahrzehnt-Tag, die 2000er Jahre, zum Action-Genre hinzufügen, um die X-Men-Daten zu verschieben. Die Methode .SubElement()
kann verwendet werden, um dieses Tag am Ende der XML-Datei hinzuzufügen.
action = root.find("./genre[@category='Action']")
new_dec = ET.SubElement(action, 'decade')
new_dec.attrib["years"] = '2000s'
print(ET.tostring(action, encoding='utf8').decode('utf8'))
<?xml version='1.0' encoding='utf8'?>
<genre category="Action">
<decade years="1980s">
<movie favorite="True" title="Indiana Jones: The raiders of the lost Ark">
<format multiple="No">DVD</format>
<year>1981</year>
<rating>PG</rating>
<description>
'Archaeologist and adventurer Indiana Jones
is hired by the U.S. government to find the Ark of the
Covenant before the Nazis.'
</description>
</movie>
<movie favorite="True" title="THE KARATE KID">
<format multiple="Yes">DVD,Online</format>
<year>1984</year>
<rating>PG</rating>
<description>None provided.</description>
</movie>
<movie favorite="False" title="Back to the Future">
<format multiple="No">Blu-ray</format>
<year>1985</year>
<rating>PG</rating>
<description>Marty McFly</description>
</movie>
</decade>
<decade years="1990s">
<movie favorite="False" title="X-Men">
<format multiple="Yes">dvd, digital</format>
<year>2000</year>
<rating>PG-13</rating>
<description>Two mutants come to a private academy for their kind whose resident superhero team must
oppose a terrorist organization with similar powers.</description>
</movie>
<movie favorite="True" title="Batman Returns">
<format multiple="No">VHS</format>
<year>1992</year>
<rating>PG13</rating>
<description>NA.</description>
</movie>
<movie favorite="False" title="Reservoir Dogs">
<format multiple="No">Online</format>
<year>1992</year>
<rating>R</rating>
<description>WhAtEvER I Want!!!?!</description>
</movie>
</decade>
<decade years="2000s" /></genre>
Füge nun den X-Men-Film zu den 2000er Jahren hinzu und entferne ihn aus den 1990er Jahren, indem du .append()
bzw. .remove()
benutzt.
xmen = root.find("./genre/decade/movie[@title='X-Men']")
dec2000s = root.find("./genre[@category='Action']/decade[@years='2000s']")
dec2000s.append(xmen)
dec1990s = root.find("./genre[@category='Action']/decade[@years='1990s']")
dec1990s.remove(xmen)
print(ET.tostring(action, encoding='utf8').decode('utf8'))
<?xml version='1.0' encoding='utf8'?>
<genre category="Action">
<decade years="1980s">
<movie favorite="True" title="Indiana Jones: The raiders of the lost Ark">
<format multiple="No">DVD</format>
<year>1981</year>
<rating>PG</rating>
<description>
'Archaeologist and adventurer Indiana Jones
is hired by the U.S. government to find the Ark of the
Covenant before the Nazis.'
</description>
</movie>
<movie favorite="True" title="THE KARATE KID">
<format multiple="Yes">DVD,Online</format>
<year>1984</year>
<rating>PG</rating>
<description>None provided.</description>
</movie>
<movie favorite="False" title="Back to the Future">
<format multiple="No">Blu-ray</format>
<year>1985</year>
<rating>PG</rating>
<description>Marty McFly</description>
</movie>
</decade>
<decade years="1990s">
<movie favorite="True" title="Batman Returns">
<format multiple="No">VHS</format>
<year>1992</year>
<rating>PG13</rating>
<description>NA.</description>
</movie>
<movie favorite="False" title="Reservoir Dogs">
<format multiple="No">Online</format>
<year>1992</year>
<rating>R</rating>
<description>WhAtEvER I Want!!!?!</description>
</movie>
</decade>
<decade years="2000s"><movie favorite="False" title="X-Men">
<format multiple="Yes">dvd, digital</format>
<year>2000</year>
<rating>PG-13</rating>
<description>Two mutants come to a private academy for their kind whose resident superhero team must
oppose a terrorist organization with similar powers.</description>
</movie>
</decade></genre>
XML-Dokumente erstellen
Schön, du hast es also geschafft, einen ganzen Film in ein neues Jahrzehnt zu verschieben. Speichere deine Änderungen wieder in der XML-Datei.
tree.write("movies.xml")
tree = ET.parse('movies.xml')
root = tree.getroot()
print(ET.tostring(root, encoding='utf8').decode('utf8'))
<?xml version='1.0' encoding='utf8'?>
<collection>
<genre category="Action">
<decade years="1980s">
<movie favorite="True" title="Indiana Jones: The raiders of the lost Ark">
<format multiple="No">DVD</format>
<year>1981</year>
<rating>PG</rating>
<description>
'Archaeologist and adventurer Indiana Jones
is hired by the U.S. government to find the Ark of the
Covenant before the Nazis.'
</description>
</movie>
<movie favorite="True" title="THE KARATE KID">
<format multiple="Yes">DVD,Online</format>
<year>1984</year>
<rating>PG</rating>
<description>None provided.</description>
</movie>
<movie favorite="False" title="Back to the Future">
<format multiple="No">Blu-ray</format>
<year>1985</year>
<rating>PG</rating>
<description>Marty McFly</description>
</movie>
</decade>
<decade years="1990s">
<movie favorite="True" title="Batman Returns">
<format multiple="No">VHS</format>
<year>1992</year>
<rating>PG13</rating>
<description>NA.</description>
</movie>
<movie favorite="False" title="Reservoir Dogs">
<format multiple="No">Online</format>
<year>1992</year>
<rating>R</rating>
<description>WhAtEvER I Want!!!?!</description>
</movie>
</decade>
<decade years="2000s"><movie favorite="False" title="X-Men">
<format multiple="Yes">dvd, digital</format>
<year>2000</year>
<rating>PG-13</rating>
<description>Two mutants come to a private academy for their kind whose resident superhero team must
oppose a terrorist organization with similar powers.</description>
</movie>
</decade></genre>
<genre category="Thriller">
<decade years="1970s">
<movie favorite="False" title="ALIEN">
<format multiple="No">DVD</format>
<year>1979</year>
<rating>R</rating>
<description>"""""""""</description>
</movie>
</decade>
<decade years="1980s">
<movie favorite="True" title="Ferris Bueller's Day Off">
<format multiple="No">DVD</format>
<year>1986</year>
<rating>PG13</rating>
<description>Funny movie about a funny guy</description>
</movie>
<movie favorite="FALSE" title="American Psycho">
<format multiple="No">blue-ray</format>
<year>2000</year>
<rating>Unrated</rating>
<description>psychopathic Bateman</description>
</movie>
</decade>
</genre>
<genre category="Comedy">
<decade years="1960s">
<movie favorite="False" title="Batman: The Movie">
<format multiple="Yes">DVD,VHS</format>
<year>1966</year>
<rating>PG</rating>
<description>What a joke!</description>
</movie>
</decade>
<decade years="2010s">
<movie favorite="True" title="Easy A">
<format multiple="No">DVD</format>
<year>2010</year>
<rating>PG--13</rating>
<description>Emma Stone = Hester Prynne</description>
</movie>
<movie favorite="True" title="Dinner for SCHMUCKS">
<format multiple="Yes">DVD,digital,Netflix</format>
<year>2011</year>
<rating>Unrated</rating>
<description>Tim (Rudd) is a rising executive
who “succeeds” in finding the perfect guest,
IRS employee Barry (Carell), for his boss’ monthly event,
a so-called “dinner for idiots,” which offers certain
advantages to the exec who shows up with the biggest buffoon.
</description>
</movie>
</decade>
<decade years="1980s">
<movie favorite="False" title="Ghostbusters">
<format multiple="Yes">Online,VHS</format>
<year>1984</year>
<rating>PG</rating>
<description>Who ya gonna call?</description>
</movie>
</decade>
<decade years="1990s">
<movie favorite="True" title="Robin Hood: Prince of Thieves">
<format multiple="No">Blu_Ray</format>
<year>1991</year>
<rating>Unknown</rating>
<description>Robin Hood slaying</description>
</movie>
</decade>
</genre>
</collection>
Was ist neu in ElementTree?
Hier findest du einen Überblick über neue Funktionen und Verbesserungen der ElementTree-Bibliothek in neueren Python-Versionen:
1. Unterstützung von XPath 1.0 (Python 3.8): Ab Python 3.8 bietet ElementTree mit den Methoden find()
und findall()
volle XPath 1.0-Unterstützung und ermöglicht so umfangreichere und komplexere XML-Abfragen. Beispiel:
# Finding all movies with a specific attribute using XPath
for movie in root.findall(".//movie[@favorite='True']"):
print(movie.attrib)
2. Verbesserungen bei Namespaces (Python 3.8+): Verbesserte Unterstützung für XML-Namespaces, die eine einfachere Interaktion mit XML-Dateien ermöglicht, die vorangestellte oder Standard-Namespaces verwenden. Beispiel:
# Register a namespace and find elements using it
ET.register_namespace('', 'http://example.com/namespace')
movies = root.findall(".//{http://example.com/namespace}movie")
3. Parser-Verbesserungen (Python 3.9): Bessere Parsing-Fehlermeldungen erleichtern die Fehlersuche in fehlerhaften XML-Dateien.
4. Neue Funktion indent()
(Python 3.9): Die Funktion xml.etree.ElementTree.indent()
wurde hinzugefügt, um XML-Dokumente durch Einrücken ihrer Elemente hübsch auszudrucken. Beispiel:
ET.indent(root, space=" ", level=0)
ET.dump(root)
5. Effizientes Parsing mit iterparse
(Python 3.10): Optimiert für Speichereffizienz, besonders nützlich bei der Arbeit mit großen XML-Dateien.
6. Erweiterte Dokumentation (Laufende Aktualisierungen): Die Python-Dokumentation für ElementTree ist jetzt umfassender und enthält Best Practices und erweiterte Anwendungsfälle.
Veraltete Funktionen in ElementTree und Alternativen
1. write() mit xml_declaration in Python 3.8+: Der Parameter xml_declaration
der Methode write()
ist veraltet, wenn die Kodierung auf 'unicode'
eingestellt ist.
- Alternative: Verwenden Sie
xml_declaration
nur, wenn die Kodierung ausdrücklich als etwas anderes als'unicode'
definiert ist.
tree.write("output.xml", encoding="utf-8", xml_declaration=True)
2. html parser: Obwohl es nicht offiziell veraltet ist, wird von der Verwendung von ElementTree für das Parsen von HTML abgeraten, da es nur begrenzt in der Lage ist, nicht wohlgeformtes HTML zu verarbeiten.
- Alternative: Verwende Bibliotheken, die speziell für das Parsen von HTML entwickelt wurden, wie z.B.
BeautifulSoup
aus dem Paketbs4
.
from bs4 import BeautifulSoup soup = BeautifulSoup(html_content, 'html.parser')
3. Workarounds für die Handhabung von Namensräumen: Ältere Methoden zur manuellen Handhabung von Namespaces (z. B. die Verkettung von Namespace-URIs mit Element-Tags) werden mit der Einführung der robusten Namespace-Unterstützung in neueren Versionen weniger empfohlen.
- Alternative: Verwende die eingebauten Methoden und Funktionen, die den Namensraum berücksichtigen.
ET.register_namespace('', 'http://example.com/namespace') movies = root.findall(".//{http://example.com/namespace}movie")
4. Manuelles Schöndrucken: Manuelle Techniken zur Einrückung und Formatierung von XML sind durch die neue Funktion indent()
(Python 3.9) überflüssig geworden.
- Alternative: Verwende
ET.indent()
für die automatische XML-Formatierung.
ET.indent(root, space=" ")
5. Direkte Verwendung von _ElementInterface: Interne Klassen wie _ElementInterface
sind nicht für den direkten Gebrauch gedacht und könnten in zukünftigen Versionen kaputt gehen.
- Alternative: Interagiere immer mit der dokumentierten öffentlichen API der ElementTree-Bibliothek.
Fazit
Es gibt einige wichtige Dinge, die du über XML und die Verwendung von ElementTree
wissen solltest.
Tags bilden die Baumstruktur und geben an, welche Werte dort beschrieben werden sollen. Eine intelligente Strukturierung kann das Lesen und Schreiben einer XML-Datei erleichtern. Tags brauchen immer öffnende und schließende Klammern, um die Beziehungen zwischen Eltern und Kindern zu zeigen.
Attribute beschreiben außerdem, wie ein Tag validiert werden kann oder ermöglichen boolesche Bezeichnungen. Attribute nehmen in der Regel ganz bestimmte Werte an, damit der XML-Parser (und der Benutzer) die Attribute zur Überprüfung der Tag-Werte verwenden kann.
ElementTree
ist eine wichtige Python-Bibliothek, mit der du ein XML-Dokument parsen und navigieren kannst. Die Verwendung von ElementTree
gliedert das XML-Dokument in eine Baumstruktur, mit der man leicht arbeiten kann. Im Zweifelsfall drucke es aus (print(ET.tostring(root, encoding='utf8').decode('utf8'))
) - verwende diese hilfreiche Druckanweisung, um das gesamte XML-Dokument auf einmal zu sehen. Es hilft bei der Überprüfung, wenn du eine XML-Datei bearbeitest, hinzufügst oder entfernst.
Jetzt bist du in der Lage, XML zu verstehen und mit dem Parsen zu beginnen!
Werde ein Python-Entwickler
FAQs
Was sind häufige Anwendungsfälle für die Verwendung von XML in der Datenwissenschaft?
XML wird in der Datenwissenschaft häufig für den Datenaustausch zwischen Systemen, Web Scraping, Konfigurationsdateien und den Umgang mit Daten mit einer komplexen, hierarchischen Struktur verwendet. Sie ist besonders nützlich, wenn du mit APIs arbeitest, die XML-Daten zurückgeben.
Kann ElementTree große XML-Dateien effizient verarbeiten?
ElementTree eignet sich für den Umgang mit mittelgroßen XML-Dateien, aber für sehr große Dateien solltest du Bibliotheken wie lxml
oder xml.sax
zu verwenden, die speichereffizienter sind und das Streaming von großen Dateien bewältigen können.
Wie schneidet ElementTree im Vergleich zu anderen XML-Parsing-Bibliotheken wie lxml oder minidom ab?
ElementTree ist Teil der Python-Standardbibliothek und für grundlegende XML-Parsing-Aufgaben einfach zu verwenden. lxml
ist leistungsfähiger und schneller und bietet zusätzliche Funktionen wie XPath 2.0-Unterstützung. minidom
ElementTree, eine weitere Standardbibliothek, basiert auf dem Document Object Model (DOM) und ist bei großen Dokumenten weniger effizient.
Was sind XPath-Ausdrücke und wie nützlich sind sie beim XML-Parsing?
XPath-Ausdrücke sind Abfragesprachen zur Auswahl von Knoten in einem XML-Dokument. Sie sind nützlich, um durch Elemente und Attribute in XML-Dokumenten zu navigieren und ermöglichen eine präzise Datenabfrage und -manipulation.
Wie kann ich ein XML-Dokument validieren, bevor ich es mit ElementTree parse?
XML-Dokumente können mithilfe einer XML Schema Definition (XSD) oder einer Document Type Definition (DTD) validiert werden. Python-Bibliotheken wie lxml
bieten integrierte Unterstützung für die Validierung gegen diese Standards.
Welche Best Practices gibt es für das Ändern von XML-Daten mit ElementTree?
Zu den besten Praktiken gehört es, an einer Kopie der XML-Daten zu arbeiten, um versehentliche Datenverluste zu vermeiden, XPath-Ausdrücke für eine präzise Navigation zu verwenden und sicherzustellen, dass bei allen Änderungen die Wohlgeformtheit des XML-Dokuments erhalten bleibt.
Kann ElementTree verwendet werden, um XML-Daten in JSON zu konvertieren?
ElementTree selbst bietet zwar keine direkte XML-zu-JSON-Konvertierung, aber du kannst die XML-Daten mit ElementTree in ein Python-Wörterbuch parsen und das Wörterbuch dann mit dem Python json
Modul.
Wie behandelt man XML-Namespaces mit ElementTree?
ElementTree kann XML-Namensräume verarbeiten, indem es das Präfix{namespace}
in Tag-Namen verwendet . Du kannst auch Namespaces mit ET.register_namespace()
registrieren, um die Handhabung von XML mit Namespaces zu erleichtern.
Was soll ich tun, wenn ich in ElementTree einen XML-Parsing-Fehler erlebe?
Überprüfe auf häufige Probleme wie fehlerhaftes XML, nicht unterstützte Kodierungen oder falsche Dateipfade. Nutze die Fehlerbehandlungsmechanismen von Python (try-except
blocks), um Parsing-Fehler zu diagnostizieren und zu verwalten.
Ist es möglich, ein XML-Dokument mithilfe von ElementTree hübsch zu drucken?
ElementTree unterstützt Pretty-Printing nicht direkt, aber du kannst mit xml.dom.minidom
verwenden, um den XML-String zu parsen und dann mit der toprettyxml()
Methode verwenden, um die XML-Zeichenfolge für die Lesbarkeit zu formatieren.
Erfahre mehr über Python
Kurs
Intermediate Python
Kurs
Introduction to Functions in Python
Der Blog
Die 20 besten Snowflake-Interview-Fragen für alle Niveaus
Nisha Arya Ahmed
20 Min.
Der Blog
Die 32 besten AWS-Interview-Fragen und Antworten für 2024
Der Blog
Top 30 Generative KI Interview Fragen und Antworten für 2024
Hesam Sheikh Hassani
15 Min.