Skip to content

15. Oefening [IMPOTS] met XML

In deze oefening, die al vele malen is behandeld, stuurt de server de resultaten terug naar de client in de vorm van een XML-stream:

  • <reponse><erreur>msg</erreur></reponse> in geval van een fout;
  • <reponse><impot>valeur</impot></reponse> als de belasting kon worden berekend.

We passen toe wat we zojuist hebben geleerd over de analyse van een XML-document.

15.1. De webservice

De webservice verschilt niet van de eerder besproken webservice, behalve dat het antwoord XML dat naar de klant wordt verzonden enigszins afwijkt. De architectuur blijft hetzelfde:


De webservice (impots_web_02)


#!D:\Programs\ActivePython\Python2.7.2\python.exe

# -*- coding=Utf-8 -*-
# de module met de Impots*-klassen importeren
from impots import *
import cgi,cgitb,re

# we staan het weergeven van debug-informatie toe
cgitb.enable()

# ------------------------------------------------ 
# de webdienst voor belastingen
# ------------------------------------------------ 

# de gegevens die nodig zijn voor de berekening van de belasting zijn in de tabel mysqL TABLE
# die deel uitmaakt van de database BASE. De tabel heeft de volgende structuur
# limieten decimal(10,2), coeffR decimal(6,2), coeffN decimal(10,2)
# de gegevens van belastingplichtigen (burgerlijke staat, aantal kinderen, jaarsalaris)
# worden door de klant verzonden in de vorm params=burgerlijke staat, aantal kinderen, jaarsalaris
# de resultaten (burgerlijke staat, aantal kinderen, jaarsalaris, te betalen belasting) worden teruggestuurd naar de klant
# in de vorm <belasting>waarde</belasting>
# of in de vorm <fout>msg</fout>, als de parameters ongeldig zijn

# de server stuurt onopgemaakte tekst terug naar de klant
print "Content-Type: text/plain\n"
# begin van het antwoord
print "<reponse>"

# definitie van de constanten
USER="root"
PWD=""
HOTE="localhost"
BASE="dbimpots"
TABLE="impots"

# instantiëring van de laag [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()

# de door de client naar de server verzonden regel wordt opgehaald
params=cgi.FieldStorage().getlist('params')
# als er geen parameters zijn, dan is er een fout
if not params:
    print "<erreur>Le parametre [params] est absent<erreur></reponse>"
    sys.exit()

# de parameter params wordt verwerkt  
#print "ontvangen parameters --> %s\n" %(params)
items=params[0].strip().lower().split(',')
# er mogen slechts 3 velden zijn
if len(items)!=3:
    print "<erreur>[%s] : nombre de parametres invalide</erreur></reponse>" % (params[0])
    sys.exit()
# de eerste parameter (burgerlijke staat) moet ja/nee zijn
marie=items[0].strip()
if marie!="oui" and marie != "non":
    print "<erreur>[%s] : 1er parametre invalide</erreur></reponse>\n"% (params[0])
    sys.exit()
# de tweede parameter (aantal kinderen) moet een geheel getal zijn
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])
# de derde parameter (salaris) moet een geheel getal zijn
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])
# de belasting wordt berekend
impot=metier.calculer(marie,enfants,salaire)
# het resultaat wordt teruggestuurd
print "<impot>%s</impot></reponse>\n" % (impot)
# einde

Opmerkingen:

Deze webservice verschilt alleen van de vorige door de aard van het antwoord:

<reponse><erreur>msg</erreur></reponse> bij een fout in plaats van <erreur>msg</erreur>

<reponse><impot>valeur</impot></reponse> als de belasting kon worden berekend in plaats van <impot>valeur</impot>

15.2. De geprogrammeerde client

Onze klant moet het door de webservice verzonden antwoord XML analyseren. We passen toe wat we hebben gezien bij de analyse van een document XML.


Het programma (client_impots_web_02)


# -*- coding=utf-8 -*-

import httplib,urllib,re
import xml.sax, xml.sax.handler
# beheersklasse XML
class XmlHandler(xml.sax.handler.ContentHandler):

    # functie die wordt aangeroepen bij het tegenkomen van een starttag
    def startElement(self,name,attributs):
        # het huidige element wordt genoteerd
        global elementcourant
        elementcourant=name.strip().lower()

    # de functie die wordt aangeroepen bij het tegenkomen van een eindtag
    def endElement(self,name):
        # er gebeurt niets
        pass

    # de functie voor gegevensbeheer
    def characters(self,data):
        # gegevens
        global elementcourant,elements

        # de gegevens worden opgehaald
        match=re.match(r"^\s*(.+?)\s*$",data)
        if match:
            elements[elementcourant]=match.groups()[0].lower()
    
def getResultatsXml(reponse):
    # het antwoord wordt geanalyseerd XML
    xml.sax.parseString(reponse,XmlHandler())
    # de resultaten worden weergegeven
    if elements.has_key('erreur'):
        return (elements['erreur'],"")
    else:
        return ("",elements['impot'])

# ------------------------------------------------------------ main
# constanten
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");
# globale variabelen
elementcourant=""
elements={}

# verbinding
connexion=httplib.HTTPConnection(HOST)
# opvolging
#connexion.set_debuglevel(1)
# we doorlopen de gegevens die naar de server moeten worden verzonden
for params in data:
    # de parameters moeten worden gecodeerd voordat ze naar de server worden verzonden
    parametres = urllib.urlencode({'params': params})
    # het verzoek wordt verzonden
    connexion.request("POST",URL,parametres)
    # verwerking van het antwoord (stream XML)
    reponse=connexion.getresponse().read()
    # verwerking van het XML-bestand
    (erreur,impot)=getResultatsXml(reponse)
    if not erreur:
        print "impot[%s]=%s" % (params,impot)
    else:
        print "erreur[%s]=%s" % (params,erreur)

Opmerkingen:

  • de XML-stroom van de webservice wordt verwerkt door de functie getResultatsXml (regel 60);
  • regel 29: de functie getResultatsXml;
  • regel 31: het antwoord XML van de webservice wordt geanalyseerd door een instantie van de klasse XmlHandler, gedefinieerd op regel 6;
  • regel 6: de klasse XmlHandler implementeert de drie methoden startElement, endElement en characters. Met behulp van deze drie methoden wordt een woordenboek aangemaakt. De sleutels zijn de namen van de tags <erreur> en <impot> en de waarden zijn de gegevens die aan deze twee tags zijn gekoppeld;
  • regels 33-36: de functie getResultatsXml retourneert een tuple met 2 elementen:
    • (erreur,"") als uit de analyse van de stream XML is gebleken dat de tag <erreur> aanwezig is. erreur vertegenwoordigt dan de inhoud van deze tag;
    • ("",impot) als uit de analyse van de stream XML is gebleken dat de tag <impot> aanwezig is. impot vertegenwoordigt dan de inhoud van deze tag.
  • regel 60: het resultaat van de functie getResultatsXml wordt opgehaald en vervolgens verwerkt in de regels 61-64.

15.3. De resultaten

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