Skip to content

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:


Il servizio web (impots_web_02)


#!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.


Il programma (client_impots_web_02)


# -*- 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.

15.3. I risultati

1
2
3
4
5
6
7
8
impot[oui,2,200000]=22504.0
impot[non,2,200000]=33388.0
impot[oui,3,200000]=16400.0
impot[non,3,200000]=22504.0
erreur[x,y,z,t]=[x,y,z,t] : nombre de parametres invalide
erreur[x,2,200000]=[x,2,200000] : 1er parametre invalide
erreur[oui,x,200000]=[oui,x,200000] : 2ieme parametre invalide
erreur[oui,2,x]=[oui,2,x] : 2ieme parametre invalide