¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
  1. Libros
  2. Python 3
  3. XML
Extrait - Python 3 Tratamiento de los datos y técnicas de programación
Extractos del libro
Python 3 Tratamiento de los datos y técnicas de programación
1 opinión
Volver a la página de compra del libro

XML

XML y las tecnologías relacionadas

1. Definición de XML, terminología asociada

XML son las siglas de eXtensible Markup Language, es decir, un lenguaje etiquetado genérico extensible. Está concebido para permitir almacenar información de cualquier naturaleza en archivos estructurados en forma de árbol mediante el uso de etiquetas cuyo nombre debe ser representativo y según ciertas reglas propias del formato XML, más los esquemas asociados al archivo XML, lo que permite realizar su validación.

Por naturaleza, un archivo XML contiene etiquetas con un nombre definido y que deben estar correctamente cerradas (<etiqueta></etiqueta>, <etiqueta />) y bien organizadas. Por ejemplo, <a><b></b></a> es una estructura válida, pero no <a><b></a></b>. Cada etiqueta de apertura junto a su cierre forma un nodo.

Este es el principio que permite construir el árbol y las relaciones entre nodos. Por ejemplo, en <a><b></b><c></c></a>, podemos decir que los nodos b y c son hermanos, que ambos son hijos de a, y que a es el padre de b y de c. Es posible, también, decir que b es el hermano izquierdo de c y que c es el hermano derecho de b. Podemos, por otro lado, decir que b y c son hojas, pues se trata de nodos que no contienen a otros nodos.

Una etiqueta puede, también, contener uno o varios atributos: <etiqueta atributo="valor" />

Más allá de estas reglas, comunes a todos los archivos XML y que forman la base, el formato se llama «extensible» porque el vocabulario y la gramática del lenguaje XML no son fijos, sino que se definen en cada documento XML mediante una referencia a este esquema, que es un elemento central.

Dicho esquema indica qué etiqueta puede estar contenida en qué lugar y, también, cuándo, qué atributos puede utilizarse en una u otra etiqueta y cuál es la naturaleza de los datos de un atributo o de una hoja.

Esto nos da una gran libertad a la hora de almacenar datos, permitiendo definir un marco de trabajo que, si se realiza correctamente, asegura en gran parte la integridad de aquellos. El esquema puede verse como una especificación a la que deben ceñirse los datos y, por consiguiente, los algoritmos que generan y leen los documentos XML asociados....

Validar un documento XML

1. Documento XML

En esta sección y las sucesivas, necesitaremos utilizar la librería lxml que podemos instalar de la siguiente manera:

$ sudo pip-3.2 install lxml 

He aquí cómo importar el componente básico:

from lxml import etree 

Para validar un documento XML, en primer lugar hay que cargarlo. Para ello, existen varios métodos. El siguiente presenta un problema cuando en la primera línea del archivo XML se especifica un encoding, dado que Python considera que esta información puede ser falsa. Es posible ver el error de la siguiente manera:

>>> with open('document.xml') as f:  
...     f.encoding  
...     f.read()  
...     f.seek(0)  
...     etree.XML(f.read())  
...   
'UTF-8'  
'<?xml version="1.0" encoding="UTF-8"?>\n'  
0  
Traceback (most recent call last):  
 File "<stdin>", line 5, in <module>  
 File "lxml.etree.pyx", line 2723, in lxml.etree.XML   
(src/lxml/lxml.etree.c:52448)  
 File "parser.pxi", line 1564, in lxml.etree._parseMemoryDocument  
(src/lxml/lxml.etree.c:79843)  
ValueError: Unicode strings with encoding declaration are not   
supported. 

El archivo declara una codificación UTF-8 en su primera línea, lo cual es cierto, según...

DOM

1. Lectura

Hemos visto la manera de parsear un archivo para validarlo. En realidad, se valida un árbol DOM. Este árbol es extremadamente importante para muchas tecnologías, como por ejemplo la tecnología JavaScript, que utiliza el árbol DOM del documento HTML como base de su trabajo (podemos verlo gracias a firebug). El código más corto es el siguiente:

>>> with open('document.xml') as f:  
...     t = etree.parse(f)  
...   
>>> root = t.getroot() 

De este modo, es posible realizar más o menos todas las operaciones que se desee. He aquí un popurrí:

>>> root.getchildren()  
[<Element persona at 0x2cce910>, <Element persona at 0x2d750f0>,  
<Element persona at 0x2dc5320>]  
>>> for c in root.iterchildren():  
...     c.getchildren(), c.text, c.values(), c.items()  
...   
([], None, ['1', 'Pablo Persona'])  
([], None, ['2', 'Joe Satriani'])  
([], None, ['3'])   
>>> root.getchildren()[0].keys()   
['id', 'nombre']   
>>> root.getchildren()[0].items()   
[('id', '1'), ('nombre', 'Pablo Persona')]   
>>> root.getchildren()[0].get('id')   ...

SAX

1. Soporte de SAX en lxml

La librería lxml está pensada para parsear archivos XML y construir árboles DOM. No obstante, dispone de las herramientas necesarias para aplicar los principios de SAX no directamente sobre el archivo XML, sino sobre el árbol DOM.

En primer lugar, se pierde la ventaja de SAX, que consiste en utilizar poca memoria cargando únicamente la etiqueta en curso, pero se aprovecha la metodología SAX, realizando una programación orientada a eventos.

El principio consiste en definir un handler que ofrece hooks que permiten al desarrollador desencadenar una acción cuando se produce un determinado evento. Este evento puede ser el principio o el final del documento, la entrada o la salida en una etiqueta, etc. La dificultad para el desarrollador reside en gestionar correctamente el evento asegurando que se encuentra donde se realmente se desea (en particular cuando es posible encontrar una etiqueta con el mismo nombre en varios niveles del árbol), y en gestionar correctamente el hecho de que el árbol se lee de manera plana y sin profundidad.

El handler se basa en la API completa de SAX y se define así:

>>> from xml.sax.handler import ContentHandler  
>>> class MyHandler(ContentHandler):   
...     def __init__(self):   
...         self.nb = 0   
...        ...

XPath

XPath es un lenguaje que permite interrogar de manera sencilla a un documento XML.

Toda la potencia de XPath se pone de manifiesto cuando el desarrollador controla la formulación de sus consultas y recupera todos los casos posibles descritos por su expresión. 

Por lo demás, la parte Python es trivial. En primer lugar, Python permite al objeto documento XML, origen de etree.parse, devolver la ruta de uno de sus nodos:

>>> xml.getpath(xml.getroot().getchildren()[1])  
'/lista/persona[2]' 

He aquí un breve apunte sobre la manera en la que se ha generado la variable xml:

>>> with open('document.xml') as f:  
...     f.readline()# se elimina la primera línea  
...     xml = etree.parse(StringIO(f.read()))  
... 

He aquí un ejemplo básico de consulta y de uso de la respuesta:

>>> element = xml.xpath('/lista/persona')  
>>> len(element)  
3  
>>> element[0].tag  
'persona' 

Un ejemplo de las funciones que pueden utilizarse en expresiones XPath:

>>> xml.xpath('count(/*/persona)')  
3.0 

Un ejemplo de iteración mediante nodos (que empiezan en 1 y no en 0):

>>> for i in range(5):  
...     expr = '/*/persona[%s]' % i  
...     print('%s: %s'...

XSLT

XSLT es el acrónimo de eXtensible Stylesheet Language Transformations y, como su propio nombre indica, se trata de un lenguaje XML que permite realizar transformaciones de estilo para traducir un documento XML, respetando cierto esquema, en otro documento que respete otro esquema distinto.

El documento XML de entrada y de salida puede tener usos particulares en lenguajes como (X)HTML o SVG, pero en ambos casos el documento debe estar bien formado, pues de no ser así resulta imposible realizar la transformación.

Si bien no está previsto en la recomendación XSLT, es posible que el formato de salida no sea un formato XML, lo que permite implementar mecanismos de transformación hacia un archivo de texto, por ejemplo.

En primer lugar, hay que cargar el documento XSLT que es XML:

>>> with open('document.xslt', 'r') as f:  
...     xslt = etree.XSLT(etree.parse(f))  
... 

A continuación, basta con utilizar el resultado para transformar nuestro documento XML:

>>> xml2 = xslt(xml, **{'fecha': '20110901'}) 

El resultado de la operación puede mostrarse en la consola:

>>> etree.tostring(xml2, pretty_print=True)   
b'<root name="lista de personas" fecha="20110901">\n  <lista>\n  
<persona>\n      <nombre>Pablo Persona</nombre>\n...

El caso concreto de los archivos HTML

1. Problemática

La historia de Internet, de la web y de la evolución del lenguaje HTML está llena de buenas intenciones e incluso, aunque existen normas (HTML 4, XHTML, XML5), es raro que se sigan realmente.

Para hacer frente a esta dificultad y para permitir un tratamiento profesional y eficaz de los flujos XML, se concibió el lenguaje XHTML, que trata de conciliar HTML y XML permitiendo construir un archivo que respete perfectamente la normal XML y que pueda parsearse sin problema, sin secciones residuales indeseables.

Los archivos HTML mal formados no pueden parsearse mediante los parsers XML clásicos. BeautifulSoup y el módulo html son dos soluciones.

Cabe destacar que el nuevo estándar HTML5 es una nueva norma que elimina la mayoría de secciones residuales de HTML4, pero mantiene algunas otras, y agrega nuevas etiquetas destinadas a mejorar la semántica (web semántica) y, sobre todo, define heurísticos que permitan interpretar de manera determinista el flujo de datos aunque no estén bien formados.

2. Parsear un archivo HTML según DOM

La librería BeautifulSoup está migrada a Python 3; he aquí cómo instalarla en la rama 2.x:

$ sudo easy_install3 BeautifulSoup4  

Parsear un archivo HTML es algo trivial:

>>> from bs4 import BeautifulSoup   
>>> with open('document.html') as f:   
...     soup = BeautifulSoup(f.read())   
... 

Además, la representación del objeto es el código parseado legible y corregido en la medida en que lo permiten los heurísticos de BeautifulSoup:

<?xml version='1.0' encoding='utf-8'?>  
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//ES"  ...