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. الجدول له البنية التالية
# حدود decimal(10,2)، coeffR decimal(6,2)، coeffN decimal(10,2)
# معلمات الأشخاص الخاضعين للضريبة (الحالة الاجتماعية، عدد الأبناء، الراتب السنوي)
# يتم إرسالها من قبل العميل بالصيغة params=الحالة الاجتماعية، عدد الأبناء، الراتب السنوي
# يتم إرسال النتائج (الحالة الاجتماعية، عدد الأبناء، الراتب السنوي، الضريبة المستحقة) إلى العميل
# بالصيغة <ضريبة>القيمة</ضريبة>
# أو في شكل <خطأ>رسالة</خطأ>، إذا كانت المعلمات غير صالحة
# يرسل الخادم نصًا غير منسق إلى العميل
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(',')
# يجب ألا يكون هناك سوى 3 حقول
if len(items)!=3:
print "<erreur>[%s] : nombre de parametres invalide</erreur></reponse>" % (params[0])
sys.exit()
# يجب أن يكون المعلمة الأولى (الحالة الاجتماعية) نعم/لا
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'])
# ------------------------------------------------------------ main
# الثوابت
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 (السطر 60)؛
- السطر 29: الدالة getResultatsXml؛
- السطر 31: يتم تحليل استجابة خدمة الويب XML بواسطة مثيل للفئة XmlHandler المُعرَّفة في السطر 6؛
- السطر 6: تُنفذ الفئة XmlHandler الطرق الثلاث startElement و endElement و characters. وبمساعدة هذه الطرق الثلاث، يتم إنشاء قاموس. المفاتيح هي أسماء العلامات <erreur> و <impot>، والقيم هي البيانات المرتبطة بهاتين العلامتين؛
- الأسطر 33-36: تُرجع الدالة getResultatsXml مجموعة مكونة من عنصرين:
- (erreur,"") إذا أظهر تحليل التدفق XML وجود العلامة <erreur>. وعندئذٍ يمثل erreur محتوى هذه العلامة؛
- ("",impot) إذا أظهر تحليل التدفق XML وجود العلامة <impot>. وعندئذٍ يمثل impot محتوى هذه العلامة.
- السطر 60: يتم استرداد نتيجة الدالة getResultatsXml ثم معالجتها في الأسطر 61-64.

