XML (Lenguaje de Marcado Extensible) es un formato estándar diseñado para almacenar y transportar datos. Se define mediante una estructura de etiquetas que permiten organizar la información de manera jerárquica. La estructura básica incluye pares de etiquetas (por ejemplo, <nodo></nodo>), atributos dentro de las etiquetas (como <nodo id="101">) y datos anidados entre ellas.
Para la manipulación de estos archivos en Python, el ecosistema estándar ofrece varias librerías:
- xml.etree.ElementTree: Es una opción ligera y eficiente, ideal para tareas simples. Funciona como una versión simplificada del modelo DOM, consumiendo menos memoria y ofreciendo una API intuitiva.
- xml.dom.*: Implementa el modelo de Documento de Objetos (DOM), cargando todo el documento en memoria como un árbol de nodos. Es útil cuando se requiere acceso aleatorio a partes del archivo.
- xml.sax.*: Utiliza un modelo basado en eventos. Es útil para archivos muy grandes, ya que no carga todo en memoria, sino que dispara eventos (como inicio de etiqueta o fin de etiqueta) a medida que lee el flujo de datos.
Escritura de documentos XML
Para generar arhcivos XML mediante programación, el módulo xml.dom.minidom facilita la creación de nodos, atributos y estructura jerárquica. A continuación, se presenta una implementación refactorizada para crear un archivo de configuración:
import xml.dom.minidom
def construir_xml_archivo(ruta_salida):
# Instanciar el documento DOM
documento = xml.dom.minidom.Document()
# Crear el elemento raíz y definir sus atributos
nodo_raiz = documento.createElement('SistemaConfig')
nodo_raiz.setAttribute('version', '2.0')
nodo_raiz.setAttribute('xmlns', 'http://ejemplo.com/esquema')
documento.appendChild(nodo_raiz)
# Crear un nodo hijo con atributos
modulo_usuario = documento.createElement('Modulo')
modulo_usuario.setAttribute('id', 'usr-001')
nodo_raiz.appendChild(modulo_usuario)
# Añadir contenido de texto al nodo hijo
texto_descripcion = documento.createTextNode('Módulo de autenticación principal')
modulo_usuario.appendChild(texto_descripcion)
# Añadir un sub-elemento dentro del módulo
etiqueta_meta = documento.createElement('MetaInfo')
etiqueta_meta.setAttribute('estado', 'activo')
modulo_usuario.appendChild(etiqueta_meta)
# Persistir el documento en disco con formato indentado
with open(ruta_salida, 'w', encoding='utf-8') as archivo:
archivo.write(documento.toprettyxml(indent=" "))
if __name__ == '__main__':
construir_xml_archivo('configuracion_generada.xml')
Este script crea una estructura jerárquica y la guarda en el disco. El uso de toprettyxml asegura que el archivo resultante tenga una sangría legible para humanos.
Lectura y parseo de documentos XML
La lectura de un archivo XML existente implica parsear el contenido y navegar por el árbol de nodos. El siguiente ejemplo muestra cómo extraer información específica, verificar atributos y distinguir entre nodos de texto y nodos de elementos:
import xml.dom.minidom
def procesar_xml_archivo(ruta_entrada):
# Cargar y parsear el archivo XML
arbol_dom = xml.dom.minidom.parse(ruta_entrada)
elemento_raiz = arbol_dom.documentElement
# Recuperar una lista de elementos por su nombre de etiqueta
lista_modulos = elemento_raiz.getElementsByTagName('Modulo')
for modulo in lista_modulos:
# Verificar y obtener atributos
if modulo.hasAttribute('id'):
id_modulo = modulo.getAttribute('id')
print(f"ID encontrado: {id_modulo}")
# Iterar sobre los nodos hijos del elemento actual
for hijo in modulo.childNodes:
# Verificar si el nodo es texto (incluido espacios en blanco)
if hijo.nodeType == hijo.TEXT_NODE:
contenido = hijo.data.strip()
if contenido:
print(f"\tContenido de texto: {contenido}")
# Si es un nodo elemento, procesar sus atributos
elif hijo.nodeType == hijo.ELEMENT_NODE:
print(f"\tSub-elemento detectado: {hijo.tagName}")
# Iterar sobre el diccionario de atributos
for nombre_attr, valor_attr in hijo.attributes.items():
print(f"\t\tPropiedad [{nombre_attr}]: {valor_attr}")
print("-" * 20)
if __name__ == '__main__':
procesar_xml_archivo('configuracion_generada.xml')