Skip to content

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 پردازش می‌شود.

15.3. نتایج

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