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 *