Leer y escribir archivos XML en Python con Pandas

L

 

Introducción

XML (Extensible Markup Language) es un lenguaje de marcado que se utiliza para almacenar datos estructurados. La biblioteca de análisis de datos de Pandas proporciona funciones para leer / escribir datos para la mayoría de los tipos de archivos.

Por ejemplo, incluye read_csv() y to_csv() para interactuar con archivos CSV. Sin embargo, Pandas no incluye ningún método para leer y escribir archivos XML.

En este artículo, veremos cómo podemos usar otros módulos para leer datos de un archivo XML y cargarlos en un Pandas DataFrame. También tomaremos datos de un Pandas DataFrame y los escribiremos en un archivo XML.

Leer XML con Pandas

Echemos un vistazo a algunas formas de leer datos XML y ponerlos en un Pandas DataFrame.

Para esta sección, usaremos un conjunto de datos de entrada para cada script. Guarde el siguiente XML en un archivo llamado properties.xml:

<?xml version="1.0" encoding="UTF-8"?>
<root>
	<bathrooms>
		<n35237 type="number">1.0</n35237>
		<n32238 type="number">3.0</n32238>
		<n44699 type="number">nan</n44699>
	</bathrooms>
	<price>
		<n35237 type="number">7020000.0</n35237>
		<n32238 type="number">10000000.0</n32238>
		<n44699 type="number">4128000.0</n44699>
	</price>
	<property_id>
		<n35237 type="number">35237.0</n35237>
		<n32238 type="number">32238.0</n32238>
		<n44699 type="number">44699.0</n44699>
	</property_id>
</root>

Leyendo con xml.etree.ElementTree

los xml.etree.ElementTree El módulo viene integrado con Python. Proporciona funcionalidad para analizar y crear documentos XML. ElementTree representa el documento XML como un árbol. Podemos movernos por el documento utilizando nodes que son elementos y subelementos del archivo XML.

En este enfoque, leemos el contenido del archivo en una variable y usamos ET.XML() para analizar el documento XML a partir de la constante de cadena. Recorreremos cada niño y sub niño manteniendo una lista de los datos que contienen. Mientras tanto, escribiendo etiquetas secundarias para la columna DataFrame. Luego escribimos estos datos en un DataFrame.

Nota: Al leer datos de XML, tenemos que transponer el DataFrame, ya que los subelementos de la lista de datos están escritos en columnas.

Veamos el código para demostrar el uso de xml.etree.ElementTree:

import xml.etree.ElementTree as ET
import pandas as pd

xml_data = open('properties.xml', 'r').read()  # Read file
root = ET.XML(xml_data)  # Parse XML

data = []
cols = []
for i, child in enumerate(root):
    data.append([subchild.text for subchild in child])
    cols.append(child.tag)

df = pd.DataFrame(data).T  # Write in DF and transpose it
df.columns = cols  # Update column names
print(df)

El código anterior producirá esta salida (varía según el archivo de entrada utilizado):

  bathrooms       price property_id
0       1.0   7020000.0     35237.0
1       3.0  10000000.0     32238.0
2       nan   4128000.0     44699.0

Leyendo con lxml

los lxml la biblioteca es un enlace de Python para las bibliotecas de C libxml2 y libxslt. También extiende la nativa ElementTree módulo. Como se trata de un módulo de terceros, deberá instalarlo con pip Me gusta esto:

$ pip install lxml

diferente a ElementTree, no leemos los datos del archivo y no los analizamos. Podemos usar directamente objectify.parse() y dale la ruta al archivo XML. Para obtener el elemento raíz, usaremos getroot() en los datos XML analizados.

Ahora podemos recorrer los elementos secundarios del node raíz y escribirlos en una lista de Python. Como antes, crearemos un DataFrame usando la lista de datos y transpondremos el DataFrame.

Veamos el código para crear un Pandas DataFrame usando lxml:

from lxml import objectify
import pandas as pd

xml_data = objectify.parse('properties.xml')  # Parse XML data
root = xml_data.getroot()  # Root element

data = []
cols = []
for i in range(len(root.getchildren())):
    child = root.getchildren()[i]
    data.append([subchild.text for subchild in child.getchildren()])
    cols.append(child.tag)

df = pd.DataFrame(data).T  # Create DataFrame and transpose it
df.columns = cols  # Update column names
print(df)

Si ejecutamos esto en el intérprete de Python, vemos el siguiente resultado:

  bathrooms       price property_id
0       1.0   7020000.0     35237.0
1       3.0  10000000.0     32238.0
2       nan   4128000.0     44699.0

Leyendo con xmltodict

los xmltodict El módulo convierte los datos XML en un diccionario Python como sugiere el nombre. Me gusta lxml, este es un módulo de terceros que debemos instalar con pip:

$ pip install xmltodict

Como hemos hecho antes, leemos el contenido XML en una variable. Damos estos datos en parse() método que devuelve un diccionario de los datos XML. Será un diccionario anidado que tiene elementos y subelementos del archivo XML. Podemos recorrer los elementos y escribirlos en una lista de datos que usamos para crear un DataFrame.

Echemos un vistazo al código para analizar datos XML para crear un DataFrame usando xmltodict:

import xmltodict
import pandas as pd

xml_data = open('properties.xml', 'r').read()  # Read data
xmlDict = xmltodict.parse(xml_data)  # Parse XML

cols = xmlDict['root'].keys()
data = []

for i in xmlDict['root']:
    child = xmlDict['root'][i]
    data.append([child[subchild]['#text'] for subchild in child])

df = pd.DataFrame(data).T  # Create DataFrame and transpose it.
df.columns = cols
print(df)

Si ejecutamos el código anterior, podemos ver el resultado como:

  bathrooms       price property_id
0       1.0   7020000.0     35237.0
1       3.0  10000000.0     32238.0
2       nan   4128000.0     44699.0

Nota: Los xmltodict no se recomienda la biblioteca para archivos XML de gran tamaño, ya que muchos desarrolladores han observado caídas de rendimiento. los lxml se considera que la biblioteca es la más rápida para trabajar con XML, incluso más rápido que el incluido xml.etree.ElementTree.

Utilice lo que sea mejor para su proyecto y, si el rendimiento es fundamental, debe ejecutar pruebas con cada biblioteca.

Escribir XML con Pandas

Veamos varias formas de escribir Pandas DataFrame en un archivo XML. Cada script que usemos a continuación creará un nuevo archivo llamado coordenadas.xml con el siguiente contenido:

<root>
  <A>
    <X>1.3</X>
    <Y>2.6</Y>
    <Z>2.1</Z>
  </A>
  <B>
    <X>1.4</X>
    <Y>1.4</Y>
    <Z>5.6</Z>
  </B>
  <C>
    <X>5.2</X>
    <Y>4.6</Y>
    <Z>4.6</Z>
  </C>
</root>

Escribir con la función write () incorporada

Podemos usar el incluido write() función para archivos para escribir un DataFrame como un archivo XML. Para lograr esto, mantendremos una lista de los datos XML, de modo que cada elemento represente una línea en XML. Luego iteraremos sobre el DataFrame y escribiremos los datos con las etiquetas de apertura y cierre apropiadas de XML en la lista de datos.

Una vez que está completo, iteramos sobre la lista una vez más para escribir los datos en el archivo XML. Aquí está el código que muestra el uso de write():

import pandas as pd

df = pd.DataFrame([[1.3, 1.4, 5.2],
                   [2.6, 1.4, 4.6],
                   [2.1, 5.6, 4.6]],
                  columns=['A', 'B', 'C'],
                  index=['X', 'Y', 'Z'])

xml_data = ['<root>']
for column in df.columns:
    xml_data.append('<{}>'.format(column))  # Opening element tag
    for field in df.index:
        # writing sub-elements
        xml_data.append('<{0}>{1}</{0}>'.format(field, df[column][field]))
    xml_data.append('</{}>'.format(column))  # Closing element tag
xml_data.append('</root>')

with open('coordinates.xml', 'w') as f:  # Writing in XML file
    for line in xml_data:
        f.write(line)

Ejecutar este código producirá un archivo llamado coordenadas.xml en el directorio actual.

Escribir archivos XML con xml.etree.ElementTree

El valor por defecto xml.etree.ElementTree El módulo se puede utilizar para almacenar datos como XML y convertirlos en una cadena para poder escribirlos en un archivo.

Nuestro primer paso es crear el elemento raíz. Luego iteramos sobre las columnas y filas del DataFrame, agregándolas como elementos y subelementos en el ElementTree. Luego convertimos el ElementTree los datos del objeto en una cadena binaria utilizando el tostring() método.

Como los datos XML son una cadena binaria, los decodificamos en UTF-8 antes de escribirlos en el archivo.

El siguiente código usa xml.etree.ElementTree para escribir un DataFrame como un archivo XML:

import xml.etree.ElementTree as ET
import pandas as pd

df = pd.DataFrame([[1.3, 1.4, 5.2],
                   [2.6, 1.4, 4.6],
                   [2.1, 5.6, 4.6]],
                  columns=['A', 'B', 'C'],
                  index=['X', 'Y', 'Z'])
header = df.columns

root = ET.Element('root')  # Root element

for column in df.columns:
    entry = ET.SubElement(root, column)  # Adding element
    for row in df.index:
        schild = row
        child = ET.SubElement(entry, schild)  # Adding sub-element
        child.text = str(df[column][schild])

xml_data = ET.tostring(root)  # binary string
with open('coordinates.xml', 'w') as f:  # Write in file as utf-8
    f.write(xml_data.decode('utf-8'))

Como antes, ejecutar este script creará un coordenadas.xml archivo con la salida esperada.

Escribir archivos XML con lxml

Utilizando lxml es similar a cómo usamos xml.etree.ElementTree. Comenzamos creando un etree objeto con el elemento raíz del archivo que estamos creando. Luego iteramos sobre el DataFrame, agregando columnas y filas como elementos y subelementos del árbol. Por último, usamos el tostring() método para obtener el etree como una cadena binaria. Escribimos el archivo después de decodificar la cadena binaria en UTF-8.

Aquí está el código para escribir DataFrame como XML usando lxml:

from lxml import etree as et
import pandas as pd

root = et.Element('root')  # Create root element
df = pd.DataFrame([[1.3, 1.4, 5.2],
                   [2.6, 1.4, 4.6],
                   [2.1, 5.6, 4.6]],
                  columns=['A', 'B', 'C'],
                  index=['X', 'Y', 'Z'])

for column in df.columns:
    entry = et.SubElement(root, column)  # Writing element
    for row in df.index:
        schild = row
        child = et.SubElement(entry, schild)  # Writing sub-elements
        child.text = str(df[column][schild])

xml_data = et.tostring(root)  # binary string
with open('coordinates.xml', 'w') as f:  # Write in XML file as utf-8
    f.write(xml_data.decode('utf-8'))

Una vez completado con éxito, verá el coordenadas.xml con las coordenadas XML.

Conclusión

Este tutorial muestra varias formas en que podemos leer y escribir datos XML con Pandas DataFrames. Puede leer datos con el xml.etree.ElementTree módulo, así como dos módulos de terceros: lxml y xmltodict.

Para escribir un Pandas DataFrame en un archivo XML, hemos utilizado un archivo convencional write() con listas, el xml.etree.ElementTree módulo, y lxml. Dado que manipular cadenas XML directamente para escribir un archivo es más propenso a errores humanos, xml.etree.ElementTree y lxml son las soluciones preferibles para exportar un DataFrame a XML.

 

About the author

Ramiro de la Vega

Bienvenido a Pharos.sh

Soy Ramiro de la Vega, Estadounidense con raíces Españolas. Empecé a programar hace casi 20 años cuando era muy jovencito.

Espero que en mi web encuentres la inspiración y ayuda que necesitas para adentrarte en el fantástico mundo de la programación y conseguir tus objetivos por difíciles que sean.

Add comment

Sobre mi

Últimos Post

Etiquetas

Esta web utiliza cookies propias para su correcto funcionamiento. Al hacer clic en el botón Aceptar, aceptas el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad