15. Ejercicio [IMPOTS] con XML
En este ejercicio, ya estudiado en numerosas ocasiones, el servidor devuelve los resultados al cliente en forma de un flujo XML:
- <respuesta><error>msg</error></respuesta> en caso de error;
- <respuesta><impuesto>valor</impuesto></respuesta> si se ha podido calcular el impuesto.
Utilizamos lo que acabamos de aprender sobre el análisis de un documento XML.
![]() |
15.1. El servicio web
El servicio web no difiere del servicio web estudiado anteriormente, salvo que la respuesta XML enviada al cliente es ligeramente diferente. La arquitectura sigue siendo la misma:
![]() |
#!D:\Programas\ActivePython\Python2.7.2\python.exe
# -*- coding=Utf-8 -*-
# importación del módulo de clases Impots*
from impots import *
import cgi,cgitb,re
# se permite la visualización de información de depuración
cgitb.enable()
# ------------------------------------------------
# el servicio web de impuestos
# ------------------------------------------------
# los datos necesarios para el cálculo del impuesto se han colocado en la tabla mysqL TABLE
# perteneciente a la base de datos BASE. La tabla tiene la siguiente estructura
# límites decimal(10,2), coeffR decimal(6,2), coeffN decimal(10,2)
# los parámetros de las personas sujetas a impuestos (estado civil, número de hijos, salario anual)
# son enviados por el cliente en el formato params=estado civil, número de hijos, salario anual
# los resultados (estado civil, número de hijos, salario anual, impuesto a pagar) se devuelven al cliente
# en el formato <impuesto>valor</impuesto>
# o en el formato <error>msg</error>, si los parámetros no son válidos
# el servidor devuelve al cliente texto sin formato
print "Content-Type: text/plain\n"
# inicio de la respuesta
print "<reponse>"
# definición de las constantes
USER="root"
PWD=""
HOTE="localhost"
BASE="dbimpots"
TABLE="impots"
# instanciación de la capa [metier]
try:
metier=ImpotsMetier(ImpotsMySQL(HOTE,USER,PWD,BASE,TABLE))
except (IOError, ImpotsError) as infos:
print ("<erreur>Une erreur s'est produite : {0}</erreur>".format(infos))
sys.exit()
# se recupera la línea enviada por el cliente al servidor
params=cgi.FieldStorage().getlist('params')
# si no hay parámetros, se produce un error
if not params:
print "<erreur>Le parametre [params] est absent<erreur></reponse>"
sys.exit()
# se procesa el parámetro params
#print "parámetros recibidos --> %s\n" %(params)
items=params[0].strip().lower().split(',')
# solo debe haber 3 campos
if len(items)!=3:
print "<erreur>[%s] : nombre de parametres invalide</erreur></reponse>" % (params[0])
sys.exit()
# el primer parámetro (estado civil) debe ser sí/no
marie=items[0].strip()
if marie!="oui" and marie != "non":
print "<erreur>[%s] : 1er parametre invalide</erreur></reponse>\n"% (params[0])
sys.exit()
# el segundo parámetro (número de hijos) debe ser un número entero
match=re.match(r"^\s*(\d+)\s*$",items[1])
if not match:
print "<erreur>[%s] : 2ieme parametre invalide</erreur></reponse>\n"% (params[0])
sys.exit()
enfants=int(match.groups()[0])
# el tercer parámetro (salario) debe ser un número entero
match=re.match(r"^\s*(\d+)\s*$",items[2])
if not match:
print "<erreur>[%s] : 2ieme parametre invalide</erreur></reponse>\n"% (params[0])
sys.exit()
salaire=int(match.groups()[0])
# se calcula el impuesto
impot=metier.calculer(marie,enfants,salaire)
# se devuelve el resultado
print "<impot>%s</impot></reponse>\n" % (impot)
# fin
Notas:
Este servicio web solo se diferencia del anterior por la naturaleza de su respuesta:
<respuesta><error>msg</error></respuesta> en caso de error, en lugar de <error>msg</error>
<respuesta><impuesto>valor</impuesto></respuesta> si se ha podido calcular el impuesto, en lugar de <impuesto>valor</impuesto>
15.2. El cliente programado
Nuestro cliente debe analizar la respuesta XML enviada por el servicio web. Aplicamos lo visto en el análisis de un documento XML.
# -*- coding=utf-8 -*-
import httplib,urllib,re
import xml.sax, xml.sax.handler
# clase de gestión XML
class XmlHandler(xml.sax.handler.ContentHandler):
# función llamada al encontrar una etiqueta de inicio
def startElement(self,name,attributs):
# se anota el elemento actual
global elementcourant
elementcourant=name.strip().lower()
# función llamada al encontrar una etiqueta de fin
def endElement(self,name):
# no se realiza ninguna acción
pass
# la función de gestión de datos
def characters(self,data):
# datos
global elementcourant,elements
# se recuperan los datos
match=re.match(r"^\s*(.+?)\s*$",data)
if match:
elements[elementcourant]=match.groups()[0].lower()
def getResultatsXml(reponse):
# se analiza la respuesta XML
xml.sax.parseString(reponse,XmlHandler())
# se devuelven los resultados
if elements.has_key('erreur'):
return (elements['erreur'],"")
else:
return ("",elements['impot'])
# ------------------------------------------------------------ main
# constantes
HOST="localhost"
URL="/cgi-bin/impots_web_02b.py"
data=("oui,2,200000","non,2,200000","oui,3,200000","non,3,200000","x,y,z,t","x,2,200000", "oui,x,200000","oui,2,x");
# variables globales
elementcourant=""
elements={}
# conexión
connexion=httplib.HTTPConnection(HOST)
# seguimiento
#connexion.set_debuglevel(1)
# se realiza un bucle sobre los datos que se van a enviar al servidor
for params in data:
# los parámetros deben codificarse antes de enviarse al servidor
parametres = urllib.urlencode({'params': params})
# envío de la solicitud
connexion.request("POST",URL,parametres)
# procesamiento de la respuesta (flujo XML)
reponse=connexion.getresponse().read()
# procesamiento del archivo xml
(erreur,impot)=getResultatsXml(reponse)
if not erreur:
print "impot[%s]=%s" % (params,impot)
else:
print "erreur[%s]=%s" % (params,erreur)
Notas:
- el flujo XML del servicio web es procesado por la función getResultatsXml (línea 60);
- línea 29: la función getResultatsXml;
- línea 31: la respuesta XML del servicio web es analizada por una instancia de la clase XmlHandler definida en la línea 6;
- línea 6: la clase XmlHandler implementa los 3 métodos startElement, endElement y characters. Con ayuda de estos 3 métodos, se crea un diccionario. Las claves son los nombres de las etiquetas <error> e <impot> y los valores son los datos asociados a estas dos etiquetas;
- líneas 33-36: la función getResultatsXml devuelve una tupla de dos elementos:
- (error, "") si el análisis del flujo XML ha detectado la existencia de la etiqueta <error>. En ese caso, error representa el contenido de dicha etiqueta;
- ("", impot) si el análisis del flujo XML ha detectado la existencia de la etiqueta <impot>. En ese caso, impot representa el contenido de dicha etiqueta.
- línea 60: se recupera el resultado de la función getResultatsXml y se procesa en las líneas 61-64.

