15. Esercizio [IMPOTS] con XML
In questo esercizio, già studiato numerose volte, il server restituisce i risultati al client sotto forma di un flusso XML:
- <reponse><erreur>msg</erreur></reponse> in caso di errore;
- <reponse><impot>valeur</impot></reponse> se l’imposta è stata calcolata con successo.
Utilizziamo quanto appena appreso sull’analisi di un documento XML.
![]() |
15.1. Il servizio web
Il servizio web non differisce da quello esaminato in precedenza, se non per il fatto che la risposta XML inviata al cliente è leggermente diversa. L’architettura rimane la stessa:
![]() |
#!D:\Programmi\ActivePython\Python2.7.2\python.exe
# -*- coding=Utf-8 -*-
# importazione del modulo delle classi Impostazioni*
from impots import *
import cgi,cgitb,re
# si abilita la visualizzazione delle informazioni di debug
cgitb.enable()
# ------------------------------------------------
# il servizio web delle imposte
# ------------------------------------------------
# i dati necessari per il calcolo dell'imposta sono stati inseriti nella tabella mysqL TABLE
# appartenente al database BASE. La tabella presenta la seguente struttura
# limiti decimal(10,2), coeffR decimal(6,2), coeffN decimal(10,2)
# i parametri relativi ai soggetti imponibili (stato civile, numero di figli, stipendio annuo)
# vengono inviati dal cliente nel formato params=stato civile, numero di figli, reddito annuo
# i risultati (stato civile, numero di figli, stipendio annuo, imposta da pagare) vengono restituiti al cliente
# nel formato <imposta>valore</imposta>
# oppure nel formato <errore>msg</errore>, se i parametri non sono validi
# il server restituisce al cliente del testo non formattato
print "Content-Type: text/plain\n"
# inizio della risposta
print "<reponse>"
# definizione delle costanti
USER="root"
PWD=""
HOTE="localhost"
BASE="dbimpots"
TABLE="impots"
# istanziazione del livello [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()
# si recupera la riga inviata dal client al server
params=cgi.FieldStorage().getlist('params')
# se non ci sono parametri, si genera un errore
if not params:
print "<erreur>Le parametre [params] est absent<erreur></reponse>"
sys.exit()
# si elabora il parametro params
#print "parametri ricevuti --> %s\n" %(params)
items=params[0].strip().lower().split(',')
# devono esserci solo 3 campi
if len(items)!=3:
print "<erreur>[%s] : nombre de parametres invalide</erreur></reponse>" % (params[0])
sys.exit()
# il primo parametro (stato civile) deve essere 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()
# il secondo parametro (numero di figli) deve essere un numero intero
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])
# il terzo parametro (stipendio) deve essere un numero intero
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])
# si calcola l'imposta
impot=metier.calculer(marie,enfants,salaire)
# si restituisce il risultato
print "<impot>%s</impot></reponse>\n" % (impot)
# fine
Note:
Questo servizio web differisce dal precedente solo per la natura della sua risposta:
<reponse><erreur>msg</erreur></reponse> in caso di errore invece di <erreur>msg</erreur>
<reponse><impot>valeur</impot></reponse> se l'imposta è stata calcolata, anziché <impot>valeur</impot>
15.2. Il client programmato
Il nostro cliente deve analizzare la risposta XML inviata dal servizio web. Applichiamo quanto visto nell’analisi di un documento XML.
# -*- coding=utf-8 -*-
import httplib,urllib,re
import xml.sax, xml.sax.handler
# classe di gestione XML
class XmlHandler(xml.sax.handler.ContentHandler):
# funzione chiamata quando si incontra un tag di inizio
def startElement(self,name,attributs):
# si registra l'elemento corrente
global elementcourant
elementcourant=name.strip().lower()
# funzione chiamata al rilevamento di un tag di chiusura
def endElement(self,name):
# non viene eseguita alcuna operazione
pass
# la funzione di gestione dei dati
def characters(self,data):
# dati
global elementcourant,elements
# i dati vengono recuperati
match=re.match(r"^\s*(.+?)\s*$",data)
if match:
elements[elementcourant]=match.groups()[0].lower()
def getResultatsXml(reponse):
# si analizza la risposta XML
xml.sax.parseString(reponse,XmlHandler())
# vengono restituiti i risultati
if elements.has_key('erreur'):
return (elements['erreur'],"")
else:
return ("",elements['impot'])
# ------------------------------------------------------------ main
# costanti
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");
# variabili globali
elementcourant=""
elements={}
# connessione
connexion=httplib.HTTPConnection(HOST)
# monitoraggio
#connexion.set_debuglevel(1)
# si esegue un ciclo sui dati da inviare al server
for params in data:
# i parametri devono essere codificati prima di essere inviati al server
parametres = urllib.urlencode({'params': params})
# invio della richiesta
connexion.request("POST",URL,parametres)
# elaborazione della risposta (flusso XML)
reponse=connexion.getresponse().read()
# elaborazione del file XML
(erreur,impot)=getResultatsXml(reponse)
if not erreur:
print "impot[%s]=%s" % (params,impot)
else:
print "erreur[%s]=%s" % (params,erreur)
Note:
- il flusso XML del servizio web viene gestito dalla funzione getResultatsXml (riga 60);
- riga 29: la funzione getResultatsXml;
- riga 31: la risposta XML del servizio web viene analizzata da un'istanza della classe XmlHandler definita alla riga 6;
- riga 6: la classe XmlHandler implementa i 3 metodi startElement, endElement, characters. Con l'aiuto di questi 3 metodi, viene creato un dizionario. Le chiavi sono i nomi dei tag <erreur> e <impot>, mentre i valori sono i dati associati a questi due tag;
- righe 33-36: la funzione getResultatsXml restituisce una tupla composta da 2 elementi:
- (erreur,"") se l'analisi del flusso XML ha rilevato la presenza del tag <erreur>. erreur rappresenta quindi il contenuto di tale tag;
- ("",impot) se l'analisi del flusso XML ha rilevato l'esistenza del tag <impot>. impot rappresenta quindi il contenuto di tale tag.
- riga 60: il risultato della funzione getResultatsXml viene recuperato e successivamente elaborato nelle righe 61-64.

