15. Exercice [IMPOTS] avec XML
Dans cet exercice déjà étudié de nombreuses fois, le serveur renvoie les résultats au client sous la forme d'un flux XML :
- <reponse><erreur>msg</erreur></reponse> en cas d'erreur ;
- <reponse><impot>valeur</impot></reponse> si l'impôt a pu être calculé.
Nous utilisons ce que nous venons d'apprendre sur l'analyse d'un document XML.
![]() |
15.1. Le service web
Le service web n'est pas différent du service web étudié précédemment si ce n'est que la réponse XML envoyée au client est légèrement différente. L'architecture reste la même :
![]() |
#!D:\Programs\ActivePython\Python2.7.2\python.exe
# -*- coding=Utf-8 -*-
# import du module des classes Impots*
from impots import *
import cgi,cgitb,re
# on autorise l'affichage d'informations de débogage
cgitb.enable()
# ------------------------------------------------
# le service web des impôts
# ------------------------------------------------
# les données nécessaires au calcul de l'impôt ont été placées dans la table mysqL TABLE
# appartenant à la base BASE. La table a la structure suivante
# limites decimal(10,2), coeffR decimal(6,2), coeffN decimal(10,2)
# les paramètres des personnes imposables (statut marital, nombre d'enfants, salaire annuel)
# sont envoyés par le client sous la forme params=statut marital, nombre d'enfants, salaire annuel
# les résultats (statut marital, nombre d'enfants, salaire annuel, impôt à payer) sont renvoyés au client
# sous la forme <impot>valeur</impot>
# ou sous la forme <erreur>msg</erreur>, si les paramètres sont invalides
# le serveur renvoie au client du texte non formaté
print "Content-Type: text/plain\n"
# début de la réponse
print "<reponse>"
# définition des constantes
USER="root"
PWD=""
HOTE="localhost"
BASE="dbimpots"
TABLE="impots"
# instanciation couche [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()
# on récupère la ligne envoyée par le client au serveur
params=cgi.FieldStorage().getlist('params')
# si pas de paramètres alors erreur
if not params:
print "<erreur>Le parametre [params] est absent<erreur></reponse>"
sys.exit()
# on exploite le paramètre params
#print "parametres recus --> %s\n" %(params)
items=params[0].strip().lower().split(',')
# il ne doit y avoir que 3 champs
if len(items)!=3:
print "<erreur>[%s] : nombre de parametres invalide</erreur></reponse>" % (params[0])
sys.exit()
# le premier paramètre (statut marital) doit être oui/non
marie=items[0].strip()
if marie!="oui" and marie != "non":
print "<erreur>[%s] : 1er parametre invalide</erreur></reponse>\n"% (params[0])
sys.exit()
# le second paramètre (nbre d'enfants) doit être un nombre entier
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])
# le troisième paramètre (salaire) doit être un nombre entier
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])
# on calcule l'impôt
impot=metier.calculer(marie,enfants,salaire)
# on renvoie le résultat
print "<impot>%s</impot></reponse>\n" % (impot)
# fin
Notes :
Ce service web ne diffère du précédent que par la nature de sa réponse :
<reponse><erreur>msg</erreur></reponse> en cas d'erreur au lieu de <erreur>msg</erreur>
<reponse><impot>valeur</impot></reponse> si l'impôt a pu être calculé au lieu de <impot>valeur</impot>
15.2. Le client programmé
Notre client doit analyser la réponse XML envoyée par le service web. Nous appliquons ce qui a été vu dans l'analyse d'un document XML.
# -*- coding=utf-8 -*-
import httplib,urllib,re
import xml.sax, xml.sax.handler
# classe de gestion XML
class XmlHandler(xml.sax.handler.ContentHandler):
# fonction appelée lors de la rencontre d'une balise de début
def startElement(self,name,attributs):
# on note l'élément courant
global elementcourant
elementcourant=name.strip().lower()
# la fonction appelée lors de la rencontre d'une balise de fin
def endElement(self,name):
# on ne fait rien
pass
# la fonction de gestion des données
def characters(self,data):
# données
global elementcourant,elements
# les données sont récupérées
match=re.match(r"^\s*(.+?)\s*$",data)
if match:
elements[elementcourant]=match.groups()[0].lower()
def getResultatsXml(reponse):
# on analyse la reponse XML
xml.sax.parseString(reponse,XmlHandler())
# on rend les résultats
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={}
# connexion
connexion=httplib.HTTPConnection(HOST)
# suivi
#connexion.set_debuglevel(1)
# on boucle sur les données à envoyer au serveur
for params in data:
# les paramètres doivent être encodés avant d'être envoyés au serveur
parametres = urllib.urlencode({'params': params})
# envoi de la requête
connexion.request("POST",URL,parametres)
# traitement de la réponse (flux XML)
reponse=connexion.getresponse().read()
# exploitation du fichier xml
(erreur,impot)=getResultatsXml(reponse)
if not erreur:
print "impot[%s]=%s" % (params,impot)
else:
print "erreur[%s]=%s" % (params,erreur)
Notes :
- le flux XML du service web est exploité par la fonction getResultatsXml (ligne 60) ;
- ligne 29 : la fonction getResultatsXml ;
- ligne 31 : la réponse XML du service web est analysée par une instance de la classe XmlHandler définie ligne 6 ;
- ligne 6 : la classe XmlHandler implémente les 3 méthodes startElement, endElement, characters. A l'aide de ces 3 méthodes, on crée un dictionnaire. Les clés sont les noms des balises <erreur> et <impot> et les valeurs sont les données associées à ces deux balises ;
- lignes 33-36 : la fonction getResultatsXml rend un tuple à 2 éléments :
- (erreur,"") si l'analyse du flux XML a montré l'existence de la balise <erreur>. erreur représente alors le contenu de cette balise ;
- ("",impot) si l'analyse du flux XML a montré l'existence de la balise <impot>. impot représente alors le contenu de cette balise.
- ligne 60 : le résultat de la fonction getResultatsXml est récupéré puis exploité lignes 61-64.

