Leer y escribir archivos XML en Python con Pandas

     

    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.

     

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *