XML, o Extensible Markup Language, es un lenguaje de marcado que se usa com煤nmente para estructurar, almacenar y transferir datos entre sistemas. Aunque no es tan com煤n como sol铆a ser, todav铆a se usa en servicios como RSS y SOAP, as铆 como para estructurar archivos como documentos de Microsoft Office.
Dado que Python es un lenguaje popular para la web y el an谩lisis de datos, es probable que necesite leer o escribir datos XML en alg煤n momento, en cuyo caso tendr谩 suerte.
A lo largo de este art铆culo, principalmente echaremos un vistazo a ElementTree m贸dulo para leer, escribir y modificar datos XML. Tambi茅n lo compararemos con el m谩s antiguo. minidom m贸dulo en las primeras secciones para que pueda obtener una buena comparaci贸n de los dos.
Los m贸dulos XML
Contenido
los minidom
, o Implementaci贸n m铆nima de DOM, es una implementaci贸n simplificada del Modelo de objetos de documento (DOM). los DOM es una interfaz de programaci贸n de aplicaciones que trata XML como una estructura de 谩rbol, donde cada node del 谩rbol es un objeto. Por lo tanto, el uso de este m贸dulo requiere que estemos familiarizados con su funcionalidad.
los ElementTree
El m贸dulo proporciona una interfaz m谩s “Pythonic” para manejar XMl y es una buena opci贸n para aquellos que no est谩n familiarizados con DOM. Tambi茅n es probable que sea un mejor candidato para que lo utilicen m谩s programadores novatos debido a su interfaz simple, que ver谩 a lo largo de este art铆culo.
En este art铆culo, el ElementTree
El m贸dulo se utilizar谩 en todos los ejemplos, mientras que minidom
tambi茅n se demostrar谩, pero solo para contar y leer documentos XML.
Ejemplo de archivo XML
En los ejemplos siguientes, utilizaremos el siguiente archivo XML, que guardaremos como “items.xml”:
<data>
<items>
<item name="item1">item1abc</item>
<item name="item2">item2abc</item>
</items>
</data>
Como puede ver, es un ejemplo de XML bastante simple, que solo contiene algunos objetos anidados y un atributo. Sin embargo, deber铆a ser suficiente para demostrar todas las operaciones XML en este art铆culo.
Leer documentos XML
Usando minidom
Para analizar un documento XML usando minidom
, primero debemos importarlo desde el xml.dom
m贸dulo. Este m贸dulo utiliza el parse
funci贸n para crear un objeto DOM a partir de nuestro archivo XML. los parse
La funci贸n tiene la siguiente sintaxis:
xml.dom.minidom.parse(filename_or_file[, parser[, bufsize]])
Aqu铆, el nombre del archivo puede ser una cadena que contenga la ruta del archivo o un objeto de tipo de archivo. La funci贸n devuelve un documento, que puede manejarse como un tipo XML. Por tanto, podemos utilizar la funci贸n getElementByTagName()
para encontrar una etiqueta espec铆fica.
Dado que cada node puede tratarse como un objeto, podemos acceder a los atributos y al texto de un elemento utilizando las propiedades del objeto. En el siguiente ejemplo, hemos accedido a los atributos y al texto de un node espec铆fico y de todos los nodes juntos.
from xml.dom import minidom
# parse an xml file by name
mydoc = minidom.parse('items.xml')
items = mydoc.getElementsByTagName('item')
# one specific item attribute
print('Item #2 attribute:')
print(items[1].attributes['name'].value)
# all item attributes
print('nAll attributes:')
for elem in items:
print(elem.attributes['name'].value)
# one specific item's data
print('nItem #2 data:')
print(items[1].firstChild.data)
print(items[1].childNodes[0].data)
# all items data
print('nAll item data:')
for elem in items:
print(elem.firstChild.data)
El resultado es el siguiente:
$ python minidomparser.py
Item #2 attribute:
item2
All attributes:
item1
item2
Item #2 data:
item2abc
item2abc
All item data:
item1abc
item2abc
Figura 1
Si quisi茅ramos usar un archivo ya abierto, simplemente podemos pasar nuestro objeto de archivo a parse
al igual que:
datasource = open('items.xml')
# parse an open file
mydoc = parse(datasource)
Adem谩s, si los datos XML ya estaban cargados como una cadena, podr铆amos haber usado el parseString()
funci贸n en su lugar.
Usando ElementTree
ElementTree
nos presenta una forma muy sencilla de procesar archivos XML. Como siempre, para poder utilizarlo primero debemos importar el m贸dulo. En nuestro c贸digo usamos el import
comando con el as
palabra clave, que nos permite usar un nombre simplificado (ET
en este caso) para el m贸dulo en el c贸digo.
Despu茅s de la importaci贸n, creamos una estructura de 谩rbol con el parse
funci贸n, y obtenemos su elemento ra铆z. Una vez que tenemos acceso al node ra铆z, podemos recorrer f谩cilmente el 谩rbol, porque un 谩rbol es un gr谩fico conectado.
Utilizando ElementTree
, y como en el ejemplo de c贸digo anterior, obtenemos los atributos del node y el texto usando los objetos relacionados con cada node.
El c贸digo es el siguiente:
import xml.etree.ElementTree as ET
tree = ET.parse('items.xml')
root = tree.getroot()
# one specific item attribute
print('Item #2 attribute:')
print(root[0][1].attrib)
# all item attributes
print('nAll attributes:')
for elem in root:
for subelem in elem:
print(subelem.attrib)
# one specific item's data
print('nItem #2 data:')
print(root[0][1].text)
# all items data
print('nAll item data:')
for elem in root:
for subelem in elem:
print(subelem.text)
El resultado ser谩 el siguiente:
$ python treeparser.py
Item #2 attribute:
item2
All attributes:
item1
item2
Item #2 data:
item2abc
All item data:
item1abc
item2abc
Figura 2
Como puede ver, esto es muy similar al minidom
ejemplo. Una de las principales diferencias es que el attrib
object es simplemente un objeto de diccionario, lo que lo hace un poco m谩s compatible con otro c贸digo de Python. Tampoco necesitamos usar value
para acceder al valor del atributo del art铆culo como lo hicimos antes.
Es posible que haya notado c贸mo acceder a objetos y atributos con ElementTree
es un poco m谩s Pythonic, como mencionamos antes. Esto se debe a que los datos XML se analizan como simples listas y diccionarios, a diferencia de minidom
donde los elementos se analizan como personalizados xml.dom.minidom.Attr
y “nodes de texto DOM”.
Contando los elementos de un documento XML
Usando minidom
Como en el caso anterior, el minidom
debe ser importado del dom
m贸dulo. Este m贸dulo proporciona la funci贸n getElementsByTagName
, que usaremos para encontrar el elemento de etiqueta. Una vez obtenido, utilizamos el len()
m茅todo incorporado para obtener el n煤mero de subelementos conectados a un node. El resultado obtenido del c贸digo siguiente se muestra en la Figura 3.
from xml.dom import minidom
# parse an xml file by name
mydoc = minidom.parse('items.xml')
items = mydoc.getElementsByTagName('item')
# total amount of items
print(len(items))
$ python counterxmldom.py
2
figura 3
Tenga en cuenta que esto solo contar谩 la cantidad de elementos secundarios debajo de la nota que ejecute len()
on, que en este caso es el node ra铆z. Si desea encontrar todos los subelementos en un 谩rbol mucho m谩s grande, deber谩 recorrer todos los elementos y contar cada uno de sus elementos secundarios.
Usando ElementTree
Del mismo modo, el ElementTree
El m贸dulo nos permite calcular la cantidad de nodes conectados a un node.
C贸digo de ejemplo:
import xml.etree.ElementTree as ET
tree = ET.parse('items.xml')
root = tree.getroot()
# total amount of items
print(len(root[0]))
El resultado es el siguiente:
$ python counterxml.py
2
Figura 4
Escribir documentos XML
Usando ElementTree
ElementTree
tambi茅n es ideal para escribir datos en archivos XML. El siguiente c贸digo muestra c贸mo crear un archivo XML con la misma estructura que el archivo que usamos en los ejemplos anteriores.
Los pasos son:
- Cree un elemento, que actuar谩 como nuestro elemento ra铆z. En nuestro caso, la etiqueta de este elemento es “datos”.
- Una vez que tenemos nuestro elemento ra铆z, podemos crear subelementos usando el
SubElement
funci贸n. Esta funci贸n tiene la sintaxis:
SubElement(parent, tag, attrib={}, **extra)
Aqu铆 parent
es el node padre al que conectarse, attrib
es un diccionario que contiene los atributos del elemento, y extra
son argumentos de palabras clave adicionales. Esta funci贸n nos devuelve un elemento, que puede usarse para adjuntar otros subelementos, como lo hacemos en las siguientes l铆neas al pasar elementos al SubElement
constructor.
3. Aunque podemos agregar nuestros atributos con el SubElement
funci贸n, tambi茅n podemos utilizar la set()
funci贸n, como lo hacemos en el siguiente c贸digo. El texto del elemento se crea con el text
propiedad de la Element
objeto.
4. En las 煤ltimas 3 l铆neas del c贸digo siguiente, creamos una cadena a partir del 谩rbol XML y escribimos esos datos en un archivo que abrimos.
C贸digo de ejemplo:
import xml.etree.ElementTree as ET
# create the file structure
data = ET.Element('data')
items = ET.SubElement(data, 'items')
item1 = ET.SubElement(items, 'item')
item2 = ET.SubElement(items, 'item')
item1.set('name','item1')
item2.set('name','item2')
item1.text="item1abc"
item2.text="item2abc"
# create a new XML file with the results
mydata = ET.tostring(data)
myfile = open("items2.xml", "w")
myfile.write(mydata)
La ejecuci贸n de este c贸digo dar谩 como resultado un nuevo archivo, “items2.xml”, que deber铆a ser equivalente al archivo “items.xml” original, al menos en t茅rminos de la estructura de datos XML. Probablemente notar谩 que la cadena resultante es solo una l铆nea y no contiene sangr铆a, sin embargo.
Encontrar elementos XML
Usando ElementTree
los ElementTree
m贸dulo ofrece el findall()
funci贸n, que nos ayuda a encontrar elementos espec铆ficos en el 谩rbol. Devuelve todos los art铆culos con la condici贸n especificada. Adem谩s, el m贸dulo tiene la funci贸n find()
, que devuelve solo el primer subelemento que coincide con los criterios especificados. La sintaxis de ambas funciones es la siguiente:
findall(match, namespaces=None)
find(match, namespaces=None)
Para ambas funciones el match
El par谩metro puede ser un nombre de etiqueta XML o una ruta. La funci贸n findall()
devuelve una lista de elementos y find
devuelve un solo objeto de tipo Element
.
Adem谩s, hay otra funci贸n auxiliar que devuelve el texto del primer node que coincide con el criterio dado:
findtext(match, default=None, namespaces=None)
Aqu铆 hay un c贸digo de ejemplo para mostrarle exactamente c贸mo operan estas funciones:
import xml.etree.ElementTree as ET
tree = ET.parse('items.xml')
root = tree.getroot()
# find the first 'item' object
for elem in root:
print(elem.find('item').get('name'))
# find all "item" objects and print their "name" attribute
for elem in root:
for subelem in elem.findall('item'):
# if we don't need to know the name of the attribute(s), get the dict
print(subelem.attrib)
# if we know the name of the attribute, access it directly
print(subelem.get('name'))
Y aqu铆 est谩 la reutilizaci贸n de ejecutar este c贸digo:
$ python findtree.py
item1
{'name': 'item1'}
item1
{'name': 'item2'}
item2
Figura 5
Modificar elementos XML
Usando ElementTree
los ElementTree
El m贸dulo presenta varias herramientas para modificar documentos XML existentes. El siguiente ejemplo muestra c贸mo cambiar el nombre de un node, cambiar el nombre de un atributo y modificar su valor, y c贸mo agregar un atributo adicional a un elemento.
El texto de un node se puede cambiar especificando el nuevo valor en el campo de texto del objeto de node. El nombre del atributo se puede redefinir utilizando el set(name, value)
funci贸n. los set
La funci贸n no tiene que trabajar solo en un atributo existente, tambi茅n se puede usar para definir un nuevo atributo.
El siguiente c贸digo muestra c贸mo realizar estas operaciones:
import xml.etree.ElementTree as ET
tree = ET.parse('items.xml')
root = tree.getroot()
# changing a field text
for elem in root.iter('item'):
elem.text="new text"
# modifying an attribute
for elem in root.iter('item'):
elem.set('name', 'newitem')
# adding an attribute
for elem in root.iter('item'):
elem.set('name2', 'newitem2')
tree.write('newitems.xml')
Despu茅s de ejecutar el c贸digo, el archivo XML resultante “newitems.xml” tendr谩 un 谩rbol XML con los siguientes datos:
<data>
<items>
<item name="newitem" name2="newitem2">new text</item>
<item name="newitem" name2="newitem2">new text</item>
</items>
</data>
Como podemos ver al comparar con el archivo XML original, los nombres de los elementos del elemento han cambiado a “nuevo elemento”, el texto a “nuevo texto” y el atributo “nombre2” se ha agregado a ambos nodes.
Tambi茅n puede notar que escribir datos XML de esta manera (llamar tree.write
con un nombre de archivo) agrega m谩s formato al 谩rbol XML para que contenga nuevas l铆neas y sangr铆a.
Creaci贸n de subelementos XML
Usando ElementTree
los ElementTree
El m贸dulo tiene m谩s de una forma de agregar un nuevo elemento. La primera forma en que veremos es usando el makeelement()
funci贸n, que tiene el nombre del node y un diccionario con sus atributos como par谩metros.
La segunda forma es a trav茅s del SubElement()
class, que toma el elemento padre y un diccionario de atributos como entradas.
En nuestro ejemplo a continuaci贸n, mostramos ambos m茅todos. En el primer caso, el node no tiene atributos, por lo que creamos un diccionario vac铆o (attrib = {}
). En el segundo caso, usamos un diccionario poblado para crear los atributos.
import xml.etree.ElementTree as ET
tree = ET.parse('items.xml')
root = tree.getroot()
# adding an element to the root node
attrib = {}
element = root.makeelement('seconditems', attrib)
root.append(element)
# adding an element to the seconditem node
attrib = {'name2': 'secondname2'}
subelement = root[0][1].makeelement('seconditem', attrib)
ET.SubElement(root[1], 'seconditem', attrib)
root[1][0].text="seconditemabc"
# create a new XML file with the new element
tree.write('newitems2.xml')
Despu茅s de ejecutar este c贸digo, el archivo XML resultante se ver谩 as铆:
<data>
<items>
<item name="item1">item1abc</item>
<item name="item2">item2abc</item>
</items>
<seconditems>
<seconditem name2="secondname2">seconditemabc</seconditem>
</seconditems>
</data>
Como podemos ver al comparar con el archivo original, se han agregado el elemento “seconditems” y su subelemento “seconditem”. Adem谩s, el node “seconditem” tiene “name2” como atributo, y su texto es “seconditemabc”, como se esperaba.
Eliminar elementos XML
Usando ElementTree
Como probablemente esperar铆a, el ElementTree
El m贸dulo tiene la funcionalidad necesaria para eliminar los atributos y subelementos del node.
Eliminar un atributo
El siguiente c贸digo muestra c贸mo eliminar el atributo de un node mediante el pop()
funci贸n. La funci贸n se aplica a la attrib
par谩metro de objeto. Especifica el nombre del atributo y lo establece en None
.
import xml.etree.ElementTree as ET
tree = ET.parse('items.xml')
root = tree.getroot()
# removing an attribute
root[0][0].attrib.pop('name', None)
# create a new XML file with the results
tree.write('newitems3.xml')
El resultado ser谩 el siguiente archivo XML:
<data>
<items>
<item>item1abc</item>
<item name="item2">item2abc</item>
</items>
</data>
Como podemos ver en el c贸digo XML anterior, el primer elemento no tiene el atributo “nombre”.
Eliminar un subelemento
Un subelemento espec铆fico se puede eliminar usando el remove
funci贸n. Esta funci贸n debe especificar el node que queremos eliminar.
El siguiente ejemplo nos muestra c贸mo usarlo:
import xml.etree.ElementTree as ET
tree = ET.parse('items.xml')
root = tree.getroot()
# removing one sub-element
root[0].remove(root[0][0])
# create a new XML file with the results
tree.write('newitems4.xml')
El resultado ser谩 el siguiente archivo XML:
<data>
<items>
<item name="item2">item2abc</item>
</items>
</data>
Como podemos ver en el c贸digo XML anterior, ahora solo hay un node de “elemento”. El segundo se ha eliminado del 谩rbol original.
Eliminar todos los subelementos
los ElementTree
m贸dulo nos presenta el clear()
funci贸n, que se puede utilizar para eliminar todos los subelementos de un elemento dado.
El siguiente ejemplo nos muestra c贸mo usar clear()
:
import xml.etree.ElementTree as ET
tree = ET.parse('items.xml')
root = tree.getroot()
# removing all sub-elements of an element
root[0].clear()
# create a new XML file with the results
tree.write('newitems5.xml')
El resultado ser谩 el siguiente archivo XML:
<data>
<items />
</data>
Como podemos ver en el c贸digo XML anterior, todos los subelementos del elemento “elementos” se han eliminado del 谩rbol.
Terminando
Python ofrece varias opciones para manejar archivos XML. En este art铆culo hemos revisado el ElementTree
m贸dulo, y lo us贸 para analizar, crear, modificar y eliminar archivos XML. Tambi茅n hemos utilizado el minidom
modelo para analizar archivos XML. Personalmente, recomiendo usar el ElementTree
m贸dulo ya que es mucho m谩s f谩cil trabajar con 茅l y es el m贸dulo m谩s moderno de los dos.