14. Обробка документів XML
![]() |
Розглянемо такий документ XML:
<tribu>
<enseignant>
<personne sexe="M">
<nom>dupont</nom>
<prenom>jean</prenom>
<age>28</age>
ceci est un commentaire
</personne>
<section>27</section>
</enseignant>
<etudiant>
<personne sexe="F">
<nom>martin</nom>
<prenom>charline</prenom>
<age>22</age>
</personne>
<formation>dess IAIE</formation>
</etudiant>
</tribu>
Ми аналізуємо цей документ, щоб отримати такий вивід у консолі:
tribu
enseignant
(personne,(sexe,M) )
nom
[dupont]
/nom
prenom
[jean]
/prenom
age
[28]
/age
/personne
section
[27]
/section
/enseignant
etudiant
(personne,(sexe,F) )
nom
[martin]
/nom
prenom
[charline]
/prenom
age
[22]
/age
/personne
formation
[dess IAIE]
/formation
/etudiant
/tribu
Нам потрібно знати, як розпізнати:
- початковий тег, наприклад <formation>;
- тег закінчення, наприклад </enseignant>;
- тег початку з атрибутами, наприклад <personne sexe="F">;
- тіло тегу, наприклад martin у <nom>martin</nom>.
Програма для аналізу коду XML називається парсером XML. Два модулі надають нам функціонал для аналізу коду XML: xml.sax та xml.sax.handler.
Модуль [xml.sax] надає нам парсер XML за допомогою інструкції:
Цей парсер послідовно аналізує текст XML. Він викликає методи користувача при таких подіях:
- метод startElement при початку тегу;
- метод endElement при кінці тегу;
- метод characters — при обробці тіла тегу.
Нам потрібно вказати парсеру клас, що реалізує ці методи:
Ми передаємо методу setContentHandler парсера екземпляр класу, що реалізує методи startElement, endElement, characters. Використовуваний клас є похідним від класу xml.sax.handler.ContentHandler. Попередні методи викликаються з параметрами:
- name — це ім’я тегу початку. attributs — це словник атрибутів тегу. Отже, для тегу <personne sexe="M"> ми отримаємо name="personne" та attributs={'sexe':'M'}
- name — це назва тегу завершення. Отже, для тегу </etudiant> отримаємо name='etudiant'.
- data — це тіло тегу. Отже, якщо тег має вигляд
, то отримаємо data='\r\n dupont\r\n '. Зазвичай пробіли, що стоять перед і після даних, видаляються.
Тепер, коли це пояснено, можна перейти до скрипта для аналізу документа XML:
# -*- coding=utf-8 -*-
import xml.sax, xml.sax.handler,re
# клас управління XML
class XmlHandler(xml.sax.handler.ContentHandler):
# функція, що викликається при виявленні тегу початку
def startElement(self,name,attributs):
global depth
# послідовність пробілів (відступ)
print " " * depth,
# атрибути
precisions=""
for (attrib,valeur) in attributs.items():
precisions+="(%s,%s) " % (attrib,valeur)
# виводиться назва тегу та можливі атрибути
if precisions :
print "(%s,%s)" % (name,precisions)
else :
print name
# додатковий рівень дерева
depth+=1
# чи це тег даних?
global balisesDonnees,baliseDeDonnees
if balisesDonnees.has_key(name.lower()):
baliseDeDonnees=1
# функція, що викликається при виявленні тегу закінчення
def endElement(self,name):
# кінець тегу
# рівень відступу
global depth
depth-=1
# послідовність пробілів (відступ)
print " " * depth,
# ім'я тегу
print "/%s" % (name)
# функція відображення даних
def characters(self,data):
# дані
global baliseDeDonnees
# чи є поточний тег тегом даних?
if not baliseDeDonnees :
return
# рівень відступу
global depth
# послідовність пробілів (відступ)
print " " * depth,
# дані відображаються
match=re.match(r"^\s*(.*)\s*$",data)
if match:
print "[%s]" % (match.groups()[0])
# кінець тегу даних
baliseDeDonnees=False
# ------------------------------------------- main
# програма
# дані
file="data.xml" # XML-файл
depth=0 # рівень втягнення = глибина в дереві
balisesDonnees={"nom":1,"prenom":1,"age":1,"section":1,"formation":1}
baliseDeDonnees=True # якщо має значення «true», вказує, що це тег даних
# створюється об’єкт аналізу XML-тексту
xml_parser=xml.sax.make_parser()
# менеджер тегів
xml_parser.setContentHandler(XmlHandler())
# обробка XML-файлу
xml_parser.parse(file)
Примітки:
- скрипт використовує бібліотеку функцій модулів xml.sax, xml.sax.handler (рядок 3);
- рядок 62: проаналізований файл XML;
- рядок 68: парсер XML;
- рядок 70: обробник подій, що генеруються парсером, буде екземпляром класу XmlHandler;
- рядок 72: розпочато аналіз документа XML;
- рядок 6: клас, що реалізує методи startElement, endElement, characters. Він походить від класу xml.sax.handler.ContentHandler, який реалізує методи, що використовуються парсером;
- рядок 9: метод startElement;
- рядок 30: метод endElement;
- рядок 41: метод characters.
Результати наведені на початку цього абзацу.
