Leer y escribir archivos XML en Python

    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

    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.

     

    Etiquetas:

    Deja una respuesta

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