curso
Tutorial de Python XML com ElementTree: Guia para iniciantes
Execute e edite o código deste tutorial online
Executar códigoComo cientista de dados, você descobrirá que o entendimento de XML é poderoso tanto para raspagem da Web quanto para a prática geral de análise de um documento estruturado.
- Você aprenderá mais sobre XML e conhecerá o pacote Python
ElementTree
. - Em seguida, você descobrirá como explorar árvores XML para entender melhor os dados com os quais está trabalhando com a ajuda das funções
ElementTree
, loops for e expressões XPath. - Em seguida, você aprenderá como modificar um arquivo XML.
- Você também utilizará expressões xpath para preencher arquivos XML.
Aprenda Python do zero
O que é XML?
XML significa "Extensible Markup Language" (Linguagem de marcação extensível). É usado principalmente em páginas da Web, onde os dados têm uma estrutura específica e são compreendidos dinamicamente pela estrutura XML.
O XML cria uma estrutura em forma de árvore que é fácil de interpretar e suporta uma hierarquia. Sempre que uma página segue XML, ela pode ser chamada de documento XML.
- Os documentos XML têm seções chamadas elementos, que são definidas por uma tag de início e uma de fim. Uma tag é uma construção de marcação que começa com
<
e termina com>
. Os caracteres entre a tag inicial e a tag final, se houver, são o conteúdo do elemento. Os elementos podem conter marcação, incluindo outros elementos, que são chamados de "elementos filhos". - O maior elemento de nível superior é chamado de raiz, que contém todos os outros elementos.
- Os atributos são pares nome-valor que existem em uma tag de início ou de elemento vazio. Um atributo XML só pode ter um único valor e cada atributo pode aparecer no máximo uma vez em cada elemento.
Para entender isso um pouco melhor, dê uma olhada no seguinte arquivo XML (abreviado):
<?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>
Pelo que você leu acima, você vê que
é o elemento raiz único: ele contém todos os outros elementos, como
, ou
, que são os elementos filhos ou subelementos. Como você pode ver, esses elementos estão aninhados.
Observe que esses elementos filhos também podem atuar como pais e conter seus próprios elementos filhos, que são chamados de "elementos subfilhos".
- Você verá que, por exemplo, o elemento
contém alguns "atributos", como
favorite
title
, que fornecem ainda mais informações!
Com essa breve introdução aos arquivos XML em mente, você está pronto para aprender mais sobre ElementTree
!
Introdução ao ElementTree
A estrutura de árvore XML torna a navegação, a modificação e a remoção relativamente simples em termos de programação. O Python tem uma biblioteca integrada, ElementTree
, que tem funções para ler e manipular XMLs (e outros arquivos com estrutura semelhante).
Primeiro, importe ElementTree
. É uma prática comum usar o alias de ET
:
import xml.etree.ElementTree as ET
Analisando dados XML
O arquivo XML fornecido descreve uma coleção básica de filmes. O único problema é que os dados estão uma bagunça! Houve muitos curadores diferentes dessa coleção, e cada um tem sua própria maneira de inserir dados no arquivo. O principal objetivo deste tutorial será ler e entender o arquivo com Python e, em seguida, corrigir os problemas.
Primeiro, você precisa ler o arquivo com ElementTree
.
tree = ET.parse('movies.xml')
root = tree.getroot()
Agora que você inicializou a árvore, deve examinar o XML e imprimir os valores para entender como a árvore está estruturada.
Cada parte de uma árvore (inclusive a raiz) tem uma tag que descreve o elemento. Além disso, como você viu na introdução, os elementos podem ter atributos, que são descritores adicionais usados especialmente para o uso repetido de tags. Os atributos também ajudam a validar os valores inseridos para essa tag, contribuindo mais uma vez para o formato estruturado de um XML.
Você verá mais adiante neste tutorial que os atributos podem ser muito poderosos quando incluídos em um XML!
root.tag
'collection'
No nível superior, você vê que esse XML está enraizado na tag collection
.
root.attrib
{}
Portanto, a raiz não tem atributos.
Para os loops
Você pode iterar facilmente sobre subelementos (comumente chamados de "filhos") na raiz usando um simples loop "for".
for child in root:
print(child.tag, child.attrib)
genre {'category': 'Action'}
genre {'category': 'Thriller'}
genre {'category': 'Comedy'}
Agora você sabe que os filhos da raiz collection
são todos genre
. Para designar o gênero, o XML usa o atributo category
. Há filmes de ação, suspense e comédia de acordo com o elemento genre
.
Normalmente, é útil que você conheça todos os elementos da árvore inteira. Uma função útil para fazer isso é root.iter()
. Você pode colocar essa função em um loop "for" e ela iterará por toda a árvore.
[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']
Isso dá uma noção geral de quantos elementos você tem, mas não mostra os atributos ou níveis na árvore.
Há uma maneira útil de ver o documento inteiro. Qualquer elemento tem um método .tostring()
. Se você passar a raiz para o método .tostring()
, poderá retornar o documento inteiro. Em ElementTree
(lembre-se do apelido ET
), .tostring()
assume uma forma um pouco estranha.
Como o ElementTree
é uma biblioteca avançada que pode interpretar mais do que apenas XML, você pode usar o XML para interpretar o XML. Você deve especificar a codificação e a decodificação do documento que está exibindo como string. Para XMLs, use 'utf8'
- Esse é o formato de documento típico para um 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>
Você pode expandir o uso da função iter()
para ajudar a encontrar elementos específicos de interesse. root.iter()
listará todos os subelementos sob a raiz que correspondem ao elemento especificado. Aqui, você listará todos os atributos do elemento movie
na árvore:
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'}
Você já pode ver como o movies
foi inserido de diferentes maneiras. Não se preocupe com isso por enquanto. Você terá a chance de corrigir um dos erros mais adiante neste tutorial.
Expressões XPath
Muitas vezes, os elementos não têm atributos, eles têm apenas conteúdo de texto. Usando o atributo .text
, você pode imprimir esse conteúdo.
Agora, imprima todas as descrições dos filmes.
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
Imprimir o XML é útil, mas o XPath é uma linguagem de consulta usada para pesquisar em um XML de forma rápida e fácil. XPath significa XML Path Language e usa, como o nome sugere, uma sintaxe "semelhante a um caminho" para identificar e navegar pelos nós em um documento XML.
A compreensão do XPath é extremamente importante para a varredura e o preenchimento de XMLs. O site ElementTree
tem uma função .findall()
que percorrerá os filhos imediatos do elemento referenciado. Você pode usar expressões XPath para especificar pesquisas mais úteis.
Aqui, você pesquisará na árvore os filmes que foram lançados em 1992:
for movie in root.findall("./genre/decade/movie/[year='1992']"):
print(movie.attrib)
{'favorite': 'True', 'title': 'Batman Returns'}
{'favorite': 'False', 'title': 'Reservoir Dogs'}
A função .findall()
sempre começa no elemento especificado. Esse tipo de função é extremamente eficiente para "localizar e substituir". Você pode até pesquisar por atributos!
Agora, imprima apenas os filmes que estão disponíveis em vários formatos (um atributo).
for movie in root.findall("./genre/decade/movie/format/[@multiple='Yes']"):
print(movie.attrib)
{'multiple': 'Yes'}
{'multiple': 'Yes'}
{'multiple': 'Yes'}
{'multiple': 'Yes'}
{'multiple': 'Yes'}
Pense em por que, nesse caso, a instrução print retorna os valores "Yes" de multiple
. Pense em como o loop "for" é definido. Você poderia reescrever esse loop para imprimir os títulos dos filmes? Experimente abaixo:
Dica: use '...'
dentro do XPath para retornar o elemento pai do elemento atual.
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'}
Modificação de um XML
Anteriormente, os títulos dos filmes eram uma bagunça absoluta. Agora, imprima-os novamente:
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'}
Corrigir o '2' em De Volta para o Futuro. Esse deve ser um problema de localização e substituição. Escreva um código para localizar o título "Back 2 the Future" e salve-o como uma variável:
b2tf = root.find("./genre/decade/movie[@title='Back 2 the Future']")
print(b2tf)
<Element 'movie' at 0x10ce00ef8>
Observe que o uso do método .find()
retorna um elemento da árvore. Na maioria das vezes, é mais útil editar o conteúdo de um elemento.
Modifique o atributo title
da variável do elemento Back 2 the Future para que você leia "Back to the Future". Em seguida, imprima os atributos de sua variável para ver a alteração. Você pode fazer isso facilmente acessando o atributo de um elemento e, em seguida, atribuindo um novo valor a ele:
b2tf.attrib["title"] = "Back to the Future"
print(b2tf.attrib)
{'favorite': 'False', 'title': 'Back to the Future'}
Escreva as alterações que você fez no XML para que elas fiquem permanentemente fixadas no documento. Imprima os atributos do filme novamente para ter certeza de que as alterações funcionaram. Use o método .write()
para fazer isso:
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'}
Fixação de atributos
O atributo multiple
está incorreto em alguns lugares. Use ElementTree
para fixar o designador com base em quantos formatos o filme tem. Primeiro, imprima o atributo format
e o texto para ver quais partes precisam ser corrigidas.
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
Há algum trabalho que precisa ser feito nessa etiqueta.
Você pode usar regex para encontrar vírgulas, que dirão se o atributo multiple
deve ser "Yes" ou "No". A adição e a modificação de atributos podem ser feitas facilmente com o método .set()
.
Observação: re
é o interpretador de regex padrão para Python. Se você quiser saber mais sobre expressões regulares, considere este tutorial.
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
Elementos móveis
Alguns dos dados foram colocados na década errada. Use o que você aprendeu sobre XML e ElementTree
para localizar e corrigir os erros de dados da década.
Será útil que você imprima as tags decade
e year
em todo o documento.
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
Os dois anos que estão na década errada são os filmes dos anos 2000. Descubra quais são esses filmes usando uma expressão XPath.
for movie in root.findall("./genre/decade/movie/[year='2000']"):
print(movie.attrib)
{'favorite': 'False', 'title': 'X-Men'}
{'favorite': 'FALSE', 'title': 'American Psycho'}
Você precisa adicionar uma nova etiqueta de década, os anos 2000, ao gênero Ação para mover os dados dos X-Men. O método .SubElement()
pode ser usado para adicionar essa tag ao final do XML.
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>
Agora, acrescente o filme X-Men à década de 2000 e remova-o da década de 1990, usando .append()
e .remove()
, respectivamente.
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>
Criar documentos XML
Legal, então você conseguiu basicamente mudar um filme inteiro para uma nova década. Salve suas alterações de volta no XML.
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>
O que há de novo no ElementTree?
Aqui está uma visão geral dos novos recursos e aprimoramentos da biblioteca ElementTree nas versões mais recentes do Python:
1. Suporte a XPath 1.0 (Python 3.8): A partir do Python 3.8, o ElementTree inclui suporte completo ao XPath 1.0 com os métodos find()
e findall()
, permitindo consultas XML mais ricas e complexas. Exemplo:
# Finding all movies with a specific attribute using XPath
for movie in root.findall(".//movie[@favorite='True']"):
print(movie.attrib)
2. Melhorias nos namespaces (Python 3.8+): Suporte aprimorado para namespaces XML, permitindo uma interação mais direta com arquivos XML que usam namespaces prefixados ou padrão. Exemplo:
# Register a namespace and find elements using it
ET.register_namespace('', 'http://example.com/namespace')
movies = root.findall(".//{http://example.com/namespace}movie")
3. Aprimoramentos do analisador (Python 3.9): A melhor análise de mensagens de erro facilita a depuração de arquivos XML malformados.
4. Nova função indent()
(Python 3.9): A função xml.etree.ElementTree.indent()
foi adicionada para imprimir documentos XML com recuo de seus elementos. Exemplo:
ET.indent(root, space=" ", level=0)
ET.dump(root)
5. Análise eficiente com iterparse
(Python 3.10): Otimizado para eficiência de memória, particularmente útil ao trabalhar com arquivos XML grandes.
6. Documentação ampliada (atualizações contínuas): A documentação do Python para o ElementTree agora é mais abrangente, incluindo práticas recomendadas e casos de uso avançados.
Recursos obsoletos no ElementTree e alternativas
1. write() com xml_declaration no Python 3.8+: O parâmetro xml_declaration
do método write()
é obsoleto quando a codificação é definida como 'unicode'
.
- Alternativa: Use
xml_declaration
somente quando a codificação for explicitamente definida como algo diferente de'unicode'
.
tree.write("output.xml", encoding="utf-8", xml_declaration=True)
2. analisador de html: Embora não seja oficialmente obsoleto, o uso do ElementTree para análise de HTML é desaconselhado porque ele é limitado no tratamento de HTML não bem formado.
- Alternativa: Use bibliotecas projetadas especificamente para análise de HTML, como
BeautifulSoup
do pacotebs4
.
from bs4 import BeautifulSoup soup = BeautifulSoup(html_content, 'html.parser')
3. Soluções alternativas de manipulação de espaço de nome: Os métodos mais antigos de manipulação manual de namespaces (por exemplo, concatenar URIs de namespace com tags de elementos) são menos recomendados com a introdução do suporte robusto a namespaces nas versões mais recentes.
- Alternativa: Use os métodos e funções incorporados com reconhecimento de espaço de nome.
ET.register_namespace('', 'http://example.com/namespace') movies = root.findall(".//{http://example.com/namespace}movie")
4. Impressão bonita manual: As técnicas manuais de recuo e formatação de XML tornaram-se obsoletas com a nova função indent()
(Python 3.9).
- Alternativa: Use
ET.indent()
para formatação automática de XML.
ET.indent(root, space=" ")
5. Uso direto de _ElementInterface: Classes internas como _ElementInterface
não se destinam ao uso direto e podem ser interrompidas em versões futuras.
- Alternativa: Sempre interaja com a API pública documentada da biblioteca ElementTree.
Conclusão
Você deve se lembrar de alguns aspectos importantes sobre XMLs e o uso do site ElementTree
.
As tags criam a estrutura da árvore e designam quais valores devem ser delineados nela. O uso da estruturação inteligente pode facilitar a leitura e a gravação de um XML. As tags sempre precisam de colchetes de abertura e fechamento para mostrar as relações entre pai e filho.
Os atributos descrevem ainda como validar uma tag ou permitem designações booleanas. Normalmente, os atributos assumem valores muito específicos para que o analisador XML (e o usuário) possa usar os atributos para verificar os valores das tags.
ElementTree
é uma importante biblioteca Python que permite que você analise e navegue em um documento XML. O uso do site ElementTree
divide o documento XML em uma estrutura de árvore que é fácil de trabalhar. Em caso de dúvida, imprima-o (print(ET.tostring(root, encoding='utf8').decode('utf8'))
) - use essa declaração de impressão útil para visualizar todo o documento XML de uma só vez. Isso ajuda você a verificar ao editar, adicionar ou remover de um XML.
Agora, você está preparado para entender o XML e começar a analisá-lo!
Torne-se um desenvolvedor Python
Perguntas frequentes
Quais são alguns casos de uso comuns de XML na ciência de dados?
O XML é usado com frequência na ciência de dados para o intercâmbio de dados entre sistemas, raspagem da Web, arquivos de configuração e manipulação de dados com uma estrutura hierárquica complexa. É particularmente útil quando você trabalha com APIs que retornam dados XML.
O ElementTree pode lidar com arquivos XML grandes de forma eficiente?
O ElementTree é adequado para lidar com arquivos XML de tamanho moderado, mas para arquivos muito grandes, você pode considerar o uso de bibliotecas como lxml
ou xml.sax
que são mais eficientes em termos de memória e podem lidar com streaming de arquivos grandes.
Como o ElementTree se compara a outras bibliotecas de análise de XML, como a lxml ou a minidom?
O ElementTree faz parte da biblioteca padrão do Python e é fácil de usar para tarefas básicas de análise de XML. lxml
O ElementTree é mais avançado e mais rápido, oferecendo recursos adicionais como suporte a XPath 2.0. minidom
O ElementTree, outra biblioteca padrão, é baseado no DOM (Document Object Model) e é menos eficiente para documentos grandes.
O que são expressões XPath e como elas são úteis na análise de XML?
As expressões XPath são linguagens de consulta para selecionar nós de um documento XML. Eles são úteis para navegar por elementos e atributos em documentos XML, permitindo a recuperação e a manipulação precisas de dados.
Como posso validar um documento XML antes de analisá-lo com o ElementTree?
Os documentos XML podem ser validados usando uma definição de esquema XML (XSD) ou uma definição de tipo de documento (DTD). As bibliotecas Python, como lxml
, oferecem suporte integrado para validação em relação a esses padrões.
Quais são as práticas recomendadas para modificar dados XML usando o ElementTree?
As práticas recomendadas incluem trabalhar em uma cópia dos dados XML para evitar a perda acidental de dados, usar expressões XPath para uma navegação precisa e garantir que todas as alterações mantenham a boa formatação do documento XML.
O ElementTree pode ser usado para converter dados XML em JSON?
Embora o ElementTree em si não ofereça conversão direta de XML para JSON, você pode analisar os dados XML em um dicionário Python usando o ElementTree e, em seguida, converter o dicionário em JSON usando o módulo json
do Python.
Como você lida com namespaces XML com o ElementTree?
O ElementTree pode lidar com namespaces XML usando o prefixo{namespace}
em nomes de tags. Você também pode registrar namespaces em ET.register_namespace()
para facilitar o manuseio de XML com namespaces.
O que devo fazer se encontrar um erro de análise de XML no ElementTree?
Verifique se há problemas comuns, como XML malformado, codificações não suportadas ou caminhos de arquivo incorretos. Use os mecanismos de tratamento de erros do Python (try-except
blocks) para diagnosticar e gerenciar erros de análise de forma elegante.
É possível imprimir um documento XML usando o ElementTree?
O ElementTree não é compatível com a impressão bonita diretamente, mas você pode usar o xml.dom.minidom
para analisar a cadeia de caracteres XML e, em seguida, usar seu método toprettyxml()
para formatar o XML para facilitar a leitura.
Saiba mais sobre Python
curso
Intermediate Python
curso
Introduction to Functions in Python
tutorial
Tutorial do Python Excel: O guia definitivo
tutorial
Tutorial do Python pandas: O guia definitivo para iniciantes
tutorial
Tutorial de análise de sentimentos com NLTK para iniciantes
tutorial
21 ferramentas essenciais do Python
tutorial
Perfilamento do Pandas (ydata-profiling) em Python: Um guia para iniciantes
Satyam Tripathi
9 min
tutorial