15. تمرین [IMPOTS] با XML
در این تمرین که پیش از این بارها پوشش داده شده است، سرور نتایج را به شکل یک جریان XML به کلاینت بازمیگرداند:
- <reponse><erreur>msg</erreur></reponse> در صورت بروز خطا؛
- <reponse><impot>valeur</impot></reponse> در صورتی که مالیات با موفقیت محاسبه شده باشد.
اکنون آنچه را که به تازگی آموختهایم بر تحلیل یک سند XML اعمال خواهیم کرد.
![]() |
15.1. سرویس وب
سرویس وب تفاوتی با مورد قبلی ندارد، به جز اینکه پاسخ XML که به کلاینت ارسال میشود کمی متفاوت است. معماری همچنان یکسان است:
![]() |
سرویس وب (impots_web_02)
#!D:\Programs\ActivePython\Python2.7.2\python.exe
# -*- coding=Utf-8 -*-
#وارد کردن ماژول کلاسهای Impots*
from impots import *
import cgi,cgitb,re
# نمایش اطلاعات اشکالزدایی را فعال میکند
cgitb.enable()
# ------------------------------------------------
#سرویس وب مالیات
# ------------------------------------------------
#دادههای مورد نیاز برای محاسبه مالیات در جدول mysqL TABLE قرار داده شدهاند.
#متعلق به پایگاه داده BASE است. جدول دارای ساختار زیر است
#limits decimal(10,2), coeffR decimal(6,2), coeffN decimal(10,2)
#پارامترهای مربوط به افراد مشمول مالیات (وضعیت تأهل، تعداد فرزندان، حقوق سالانه)
# توسط مشتری در قالب پارامترها ارسال میشوند: وضعیت تأهل، تعداد فرزندان، حقوق سالانه
#نتایج (وضعیت تأهل، تعداد فرزندان، حقوق سالانه، مالیات قابل پرداخت) به مشتری بازگردانده میشوند
# در قالب <tax>value</tax>
#یا در قالب <error>msg</error>، اگر پارامترها نامعتبر باشند
# سرور متن بدون قالببندی را به کلاینت بازمیگرداند
print "Content-Type: text/plain\n"
# شروع پاسخ
print "<reponse>"
# تعریف ثابتها
USER="root"
PWD=""
HOTE="localhost"
BASE="dbimpots"
TABLE="impots"
# مثالسازی لایه [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()
#بازیابی خط ارسالشده توسط کلاینت به سرور
params=cgi.FieldStorage().getlist('params')
# اگر هیچ پارامتری وجود نداشته باشد، خطا
if not params:
print "<erreur>Le parametre [params] est absent<erreur></reponse>"
sys.exit()
# پردازش پارامتر 'params'
#print "پارامترهای دریافتی --> %s\n" %(params)
items=params[0].strip().lower().split(',')
# فقط باید ۳ فیلد وجود داشته باشد
if len(items)!=3:
print "<erreur>[%s] : nombre de parametres invalide</erreur></reponse>" % (params[0])
sys.exit()
# پارامتر اول (وضعیت تأهل) باید yes/no باشد
marie=items[0].strip()
if marie!="oui" and marie != "non":
print "<erreur>[%s] : 1er parametre invalide</erreur></reponse>\n"% (params[0])
sys.exit()
# پارامتر دوم (تعداد فرزندان) باید یک عدد صحیح باشد
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])
# پارامتر سوم (حقوق) باید یک عدد صحیح باشد
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])
#مالیات محاسبه میشود
impot=metier.calculer(marie,enfants,salaire)
# نتیجه بازگردانده میشود
print "<impot>%s</impot></reponse>\n" % (impot)
# پایان
یادداشتها:
این سرویس وب تنها در ماهیت پاسخ خود با مورد قبلی متفاوت است:
<reponse><erreur>msg</erreur></reponse> در صورت بروز خطا، به جای <erreur>msg</erreur>
<reponse><impot>valeur</impot></reponse> اگر مالیات محاسبه شده باشد، به جای <impot>valeur</impot>
15.2. برنامهٔ مشتری
کلاینت ما باید پاسخ XML ارسالشده توسط سرویس وب را تحلیل کند. ما اصول پوششدادهشده در تحلیل یک سند XML را اعمال میکنیم.
برنامه (client_impots_web_02)
# -*- coding=utf-8 -*-
import httplib,urllib,re
import xml.sax, xml.sax.handler
# کلاس مدیریت XML
class XmlHandler(xml.sax.handler.ContentHandler):
# تابعی که هنگام برخورد با یک تگ باز فراخوانی میشود
def startElement(self,name,attributs):
# عنصر فعلی ثبت میشود
global elementcourant
elementcourant=name.strip().lower()
# تابعی که هنگام برخورد با تگ پایانی فراخوانی میشود
def endElement(self,name):
# هیچ کاری انجام نمیدهد
pass
# تابع مدیریت دادهها
def characters(self,data):
# دادهها
global elementcourant,elements
# دادهها بازیابی میشوند
match=re.match(r"^\s*(.+?)\s*$",data)
if match:
elements[elementcourant]=match.groups()[0].lower()
def getResultatsXml(reponse):
# تحلیل پاسخ XML
xml.sax.parseString(reponse,XmlHandler())
#نتایج بازگردانده میشوند
if elements.has_key('erreur'):
return (elements['erreur'],"")
else:
return ("",elements['impot'])
# ------------------------------------------------------------ اصلی
#ثابتها
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");
# متغیرهای سراسری
elementcourant=""
elements={}
#اتصال
connexion=httplib.HTTPConnection(HOST)
# ردیابی
#connexion.set_debuglevel(1)
# حلقه زدن روی دادهها برای ارسال به سرور
for params in data:
#پارامترها باید قبل از ارسال به سرور رمزگذاری شوند
parametres = urllib.urlencode({'params': params})
#ارسال درخواست
connexion.request("POST",URL,parametres)
#پردازش پاسخ (جریان XML)
reponse=connexion.getresponse().read()
#پردازش فایل XML
(erreur,impot)=getResultatsXml(reponse)
if not erreur:
print "impot[%s]=%s" % (params,impot)
else:
print "erreur[%s]=%s" % (params,erreur)
یادداشتها:
- جریان XML از سرویس وب توسط تابع getResultatsXml (خط ۶۰) پردازش میشود؛
- خط ۲۹: تابع getResultatsXml;
- خط ۳۱: پاسخ سرویس وب XML توسط یک نمونه از کلاس XmlHandler که در خط ۶ تعریف شده است، تحلیل میشود؛
- خط ۶: کلاس XmlHandler سه متد startElement، endElement و characters را پیادهسازی میکند. با استفاده از این سه متد، یک فرهنگ لغت ایجاد میشود. کلیدها نام تگهای <erreur> و <impot> هستند و مقادیر، دادههای مرتبط با این دو تگ میباشند؛
- خطوط ۳۳–۳۶: تابع getResultatsXml یک تپل با دو عنصر برمیگرداند:
- (erreur,"") اگر تحلیل جریان XML وجود برچسب <erreur> را آشکار کرد. سپس erreur محتوای این برچسب را نشان میدهد؛
- ("",impot) اگر تحلیل جریان XML وجود تگ <impot> را آشکار کرد. سپس impot محتوای این تگ را نشان میدهد.
- خط 60: نتیجه تابع getResultatsXml بازیابی شده و سپس در خطوط 61–64 پردازش میشود.

