Skip to content

15. Übung [IMPOTS] mit XML

In dieser bereits mehrfach behandelten Übung sendet der Server die Ergebnisse in Form eines XML-Datenstroms an den Client zurück:

  • <reponse><erreur>msg</erreur></reponse> im Fehlerfall;
  • <reponse><impot>valeur</impot></reponse>, wenn die Steuer berechnet werden konnte.

Wir wenden das soeben Gelernte auf die Analyse eines XML-Dokuments an.

15.1. Der Webservice

Der Webdienst unterscheidet sich nicht von dem zuvor behandelten Webdienst, abgesehen davon, dass die an den Client gesendete Antwort XML geringfügig abweicht. Die Architektur bleibt dieselbe:


Der Webdienst (impots_web_02)


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

# -*- coding=Utf-8 -*-
# Import des Moduls „Impots*“
from impots import *
import cgi,cgitb,re

# Anzeige von Debugging-Informationen zulassen
cgitb.enable()

# ------------------------------------------------ 
# Der Webdienst der Steuerbehörde
# ------------------------------------------------ 

# Die für die Steuerberechnung erforderlichen Daten wurden in die Tabelle mysqL TABLE
# der Datenbank BASE. Die Tabelle hat folgende Struktur
# Grenzwerte decimal(10,2), coeffR decimal(6,2), coeffN decimal(10,2)
# die Angaben zu den Steuerpflichtigen (Familienstand, Anzahl der Kinder, Jahresgehalt)
# werden vom Kunden in der Form „params=Familienstand, Anzahl der Kinder, Jahresgehalt“ übermittelt
# Die Ergebnisse (Familienstand, Anzahl der Kinder, Jahresgehalt, zu zahlende Steuer) werden an den Kunden zurückgesendet
# in der Form <Steuer>Wert</Steuer>
# oder in der Form <Fehler>Meldung</Fehler>, wenn die Parameter ungültig sind

# Der Server sendet unformatierten Text an den Client zurück
print "Content-Type: text/plain\n"
# Beginn der Antwort
print "<reponse>"

# Definition der Konstanten
USER="root"
PWD=""
HOTE="localhost"
BASE="dbimpots"
TABLE="impots"

# Instanziierung der Schicht [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()

# Die vom Client an den Server gesendete Zeile wird abgerufen
params=cgi.FieldStorage().getlist('params')
# Wenn keine Parameter vorhanden sind, wird ein Fehler ausgegeben
if not params:
    print "<erreur>Le parametre [params] est absent<erreur></reponse>"
    sys.exit()

# Der Parameter „params“ wird ausgewertet  
#print "Empfangene Parameter --> %s\n" %(params)
items=params[0].strip().lower().split(',')
# Es dürfen nur 3 Felder vorhanden sein
if len(items)!=3:
    print "<erreur>[%s] : nombre de parametres invalide</erreur></reponse>" % (params[0])
    sys.exit()
# Der erste Parameter (Familienstand) muss „ja“ oder „nein“ sein
marie=items[0].strip()
if marie!="oui" and marie != "non":
    print "<erreur>[%s] : 1er parametre invalide</erreur></reponse>\n"% (params[0])
    sys.exit()
# Der zweite Parameter (Anzahl der Kinder) muss eine ganze Zahl sein
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])
# Der dritte Parameter (Gehalt) muss eine ganze Zahl sein
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])
# Die Steuer wird berechnet
impot=metier.calculer(marie,enfants,salaire)
# Das Ergebnis wird zurückgegeben
print "<impot>%s</impot></reponse>\n" % (impot)
# Ende

Anmerkungen:

Dieser Webdienst unterscheidet sich vom vorherigen lediglich durch die Art seiner Antwort:

<reponse><erreur>msg</erreur></reponse> im Fehlerfall anstelle von <erreur>msg</erreur>

<reponse><impot>valeur</impot></reponse>, wenn die Steuer berechnet werden konnte, anstelle von <impot>valeur</impot>

15.2. Der programmierte Client

Unser Client muss die vom Webdienst gesendete Antwort XML analysieren. Wir wenden dabei das an, was wir bei der Analyse eines Dokuments XML gesehen haben.


Das Programm (client_impots_web_02)


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

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

    # Funktion, die beim Auftreten eines Start-Tags aufgerufen wird
    def startElement(self,name,attributs):
        # das aktuelle Element wird notiert
        global elementcourant
        elementcourant=name.strip().lower()

    # die Funktion, die beim Auftreten eines End-Tags aufgerufen wird
    def endElement(self,name):
        # Es wird nichts unternommen
        pass

    # die Funktion zur Datenverwaltung
    def characters(self,data):
        # Daten
        global elementcourant,elements

        # Die Daten werden abgerufen
        match=re.match(r"^\s*(.+?)\s*$",data)
        if match:
            elements[elementcourant]=match.groups()[0].lower()
    
def getResultatsXml(reponse):
    # die Antwort wird analysiert XML
    xml.sax.parseString(reponse,XmlHandler())
    # die Ergebnisse werden ausgegeben
    if elements.has_key('erreur'):
        return (elements['erreur'],"")
    else:
        return ("",elements['impot'])

# ------------------------------------------------------------ main
# Konstanten
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 Variablen
elementcourant=""
elements={}

# Verbindung
connexion=httplib.HTTPConnection(HOST)
# Nachverfolgung
#connexion.set_debuglevel(1)
# Es wird eine Schleife über die an den Server zu sendenden Daten durchlaufen
for params in data:
    # Die Parameter müssen vor dem Senden an den Server kodiert werden
    parametres = urllib.urlencode({'params': params})
    # Senden der Anfrage
    connexion.request("POST",URL,parametres)
    # Verarbeitung der Antwort (Datenstrom XML)
    reponse=connexion.getresponse().read()
    # Auswertung der XML-Datei
    (erreur,impot)=getResultatsXml(reponse)
    if not erreur:
        print "impot[%s]=%s" % (params,impot)
    else:
        print "erreur[%s]=%s" % (params,erreur)

Anmerkungen:

  • Der Webservice-Flow XML wird von der Funktion getResultatsXml (Zeile 60) verarbeitet;
  • Zeile 29: die Funktion getResultatsXml;
  • Zeile 31: Die Antwort XML des Webdienstes wird von einer Instanz der in Zeile 6 definierten Klasse XmlHandler analysiert;
  • Zeile 6: Die Klasse XmlHandler implementiert die drei Methoden startElement, endElement und characters. Mit Hilfe dieser drei Methoden wird ein Dictionary erstellt. Die Schlüssel sind die Namen der Tags <erreur> und <impot>, und die Werte sind die diesen beiden Tags zugeordneten Daten;
  • Zeilen 33–36: Die Funktion getResultatsXml gibt ein Tupel mit zwei Elementen zurück:
    • (erreur,""), wenn die Analyse des Datenstroms XML das Vorhandensein des Tags <erreur> ergeben hat. erreur stellt dann den Inhalt dieses Tags dar;
    • ("",impot), wenn die Analyse des Datenstroms XML das Vorhandensein des Tags <impot> ergeben hat. impot stellt dann den Inhalt dieses Tags dar.
  • Zeile 60: Das Ergebnis der Funktion getResultatsXml wird abgerufen und anschließend in den Zeilen 61–64 ausgewertet.

15.3. Die Ergebnisse

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