15. Ćwiczenie [IMPOTS] z XML
W tym ćwiczeniu, które było już wielokrotnie omawiane, serwer zwraca wyniki do klienta w postaci strumienia XML:
- <reponse><erreur>msg</erreur></reponse> w przypadku błędu;
- <reponse><impot>valeur</impot></reponse>, jeśli udało się obliczyć podatek.
Wykorzystujemy to, czego właśnie się nauczyliśmy, do analizy dokumentu XML.
![]() |
15.1. Usługa internetowa
Usługa internetowa nie różni się od omówionej wcześniej, z wyjątkiem tego, że odpowiedź XML wysyłana do klienta jest nieco inna. Architektura pozostaje taka sama:
![]() |
#!D:\Programs\ActivePython\Python2.7.2\python.exe
# -*- coding=Utf-8 -*-
# import modułu klas Impots*
from impots import *
import cgi,cgitb,re
# zezwalamy na wyświetlanie informacji debugowania
cgitb.enable()
# ------------------------------------------------
# serwis internetowy urzędu skarbowego
# ------------------------------------------------
# dane niezbędne do obliczenia podatku zostały umieszczone w tabeli mysqL TABLE
# należącej do bazy danych BASE. Tabela ma następującą strukturę
# limity decimal(10,2), coeffR decimal(6,2), coeffN decimal(10,2)
# parametry osób podlegających opodatkowaniu (stan cywilny, liczba dzieci, roczne wynagrodzenie)
# są przesyłane przez klienta w postaci params=stan cywilny, liczba dzieci, roczne wynagrodzenie
# wyniki (stan cywilny, liczba dzieci, roczne wynagrodzenie, podatek do zapłaty) są zwracane klientowi
# w postaci <podatek>wartość</podatek>
# lub w postaci <błąd>msg</błąd>, jeśli parametry są nieprawidłowe
# serwer zwraca klientowi tekst nieformatowany
print "Content-Type: text/plain\n"
# początek odpowiedzi
print "<reponse>"
# definicja stałych
USER="root"
PWD=""
HOTE="localhost"
BASE="dbimpots"
TABLE="impots"
# utworzenie instancji warstwy [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()
# odbieramy wiersz wysłany przez klienta do serwera
params=cgi.FieldStorage().getlist('params')
# jeśli nie ma parametrów, to błąd
if not params:
print "<erreur>Le parametre [params] est absent<erreur></reponse>"
sys.exit()
# przetwarzamy parametr params
#print "otrzymane parametry --> %s\n" %(params)
items=params[0].strip().lower().split(',')
# powinny być tylko 3 pola
if len(items)!=3:
print "<erreur>[%s] : nombre de parametres invalide</erreur></reponse>" % (params[0])
sys.exit()
# pierwszy parametr (stan cywilny) musi mieć wartość „tak” lub „nie”
marie=items[0].strip()
if marie!="oui" and marie != "non":
print "<erreur>[%s] : 1er parametre invalide</erreur></reponse>\n"% (params[0])
sys.exit()
# drugi parametr (liczba dzieci) musi być liczbą całkowitą
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])
# trzeci parametr (wynagrodzenie) musi być liczbą całkowitą
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])
# obliczamy podatek
impot=metier.calculer(marie,enfants,salaire)
# zwracamy wynik
print "<impot>%s</impot></reponse>\n" % (impot)
# koniec
Uwagi:
Ta usługa internetowa różni się od poprzedniej jedynie charakterem odpowiedzi:
<reponse><erreur>msg</erreur></reponse> w przypadku błędu zamiast <erreur>msg</erreur>
<reponse><impot>valeur</impot></reponse>, jeśli udało się obliczyć podatek, zamiast <impot>valeur</impot>
15.2. Klient programowy
Nasz klient musi przeanalizować odpowiedź XML przesłaną przez serwis internetowy. Stosujemy to, co omówiono podczas analizy dokumentu XML.
# -*- coding=utf-8 -*-
import httplib,urllib,re
import xml.sax, xml.sax.handler
# klasa zarządzania XML
class XmlHandler(xml.sax.handler.ContentHandler):
# funkcja wywoływana po napotkaniu znacznika początkowego
def startElement(self,name,attributs):
# zapisywany jest bieżący element
global elementcourant
elementcourant=name.strip().lower()
# funkcja wywoływana po napotkaniu znacznika końcowego
def endElement(self,name):
# nie wykonuje się żadnej czynności
pass
# funkcja zarządzania danymi
def characters(self,data):
# dane
global elementcourant,elements
# dane są pobierane
match=re.match(r"^\s*(.+?)\s*$",data)
if match:
elements[elementcourant]=match.groups()[0].lower()
def getResultatsXml(reponse):
# analizowana jest odpowiedź XML
xml.sax.parseString(reponse,XmlHandler())
# wyniki są zwracane
if elements.has_key('erreur'):
return (elements['erreur'],"")
else:
return ("",elements['impot'])
# ------------------------------------------------------------ main
# stałe
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");
# zmienne globalne
elementcourant=""
elements={}
# połączenie
connexion=httplib.HTTPConnection(HOST)
# śledzenie
#connexion.set_debuglevel(1)
# przechodzimy do pętli przetwarzania danych, które mają zostać wysłane do serwera
for params in data:
# parametry muszą zostać zakodowane przed wysłaniem na serwer
parametres = urllib.urlencode({'params': params})
# wysyłanie żądania
connexion.request("POST",URL,parametres)
# przetwarzanie odpowiedzi (strumień XML)
reponse=connexion.getresponse().read()
# przetwarzanie pliku XML
(erreur,impot)=getResultatsXml(reponse)
if not erreur:
print "impot[%s]=%s" % (params,impot)
else:
print "erreur[%s]=%s" % (params,erreur)
Uwagi:
- strumień XML serwisu internetowego jest obsługiwany przez funkcję getResultatsXml (wiersz 60);
- wiersz 29: funkcja getResultatsXml;
- wiersz 31: odpowiedź XML z serwisu internetowego jest analizowana przez instancję klasy XmlHandler zdefiniowanej w wierszu 6;
- wiersz 6: klasa XmlHandler implementuje trzy metody: startElement, endElement oraz characters. Za pomocą tych trzech metod tworzony jest słownik. Kluczami są nazwy tagów <erreur> i <impot>, a wartościami są dane powiązane z tymi dwoma tagami;
- wiersze 33–36: funkcja getResultatsXml zwraca krotkę zawierającą 2 elementy:
- (erreur,""), jeśli analiza strumienia XML wykazała obecność tagu <erreur>. erreur reprezentuje wówczas zawartość tego tagu;
- ("",impot), jeśli analiza strumienia XML wykazała obecność tagu <impot>. impot reprezentuje wówczas zawartość tego tagu.
- wiersz 60: wynik funkcji getResultatsXml jest pobierany, a następnie przetwarzany w wierszach 61–64.

