14. Przetwarzanie dokumentów XML
![]() |
Rozważmy następujący dokument 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>
Analizujemy ten dokument, aby uzyskać następujący wynik na konsoli:
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
Musimy wiedzieć, jak rozpoznać:
- tag początkowy, taki jak <kształcenie>;
- tag końcowy, taki jak </nauczyciel>;
- tag początkowy z atrybutami, np. <osoba płeć="F">;
- treść tagu, np. martin w <nom>martin</nom>.
Program służący do analizy kodu XML nazywa się parserem XML. Dwa moduły zapewniają nam funkcje potrzebne do analizy kodu XML: xml.sax i xml.sax.handler.
Moduł [xml.sax] udostępnia nam parser XML za pomocą instrukcji:
Ten parser analizuje tekst XML sekwencyjnie. Wywołuje metody użytkownika w odpowiedzi na zdarzenia:
- metodę startElement przy rozpoczęciu tagu;
- metodę endElement przy zakończeniu tagu;
- metodę characters w treści tagu.
Musimy wskazać parserowi klasę implementującą te metody:
Przekazujemy do metody setContentHandler parsera instancję klasy implementującej metody startElement, endElement, characters. Wykorzystywana klasa jest klasą pochodną klasy xml.sax.handler.ContentHandler. Powyższe metody są wywoływane z następującymi parametrami:
- name to nazwa tagu początkowego. attributs to słownik atrybutów tego tagu. Tak więc dla tagu <personne sexe="M"> otrzymamy name="personne" i attributs={'sexe':'M'}
- name to nazwa tagu końcowego. Tak więc dla tagu </etudiant> otrzymamy name='etudiant'.
- „data” to treść znacznika. Tak więc, jeśli znacznik ma postać
otrzymamy data='\r\n dupont\r\n '. Zazwyczaj usuwa się spacje przed i po danych.
Po tym wyjaśnieniu możemy przejść do skryptu analizującego dokument XML:
# -*- coding=utf-8 -*-
import xml.sax, xml.sax.handler,re
# klasa zarządzania XML
class XmlHandler(xml.sax.handler.ContentHandler):
# funkcja wywoływana po napotkaniu znacznika początkowego
def startElement(self,name,attributs):
global depth
# sekwencja spacji (wcięcie)
print " " * depth,
# atrybuty
precisions=""
for (attrib,valeur) in attributs.items():
precisions+="(%s,%s) " % (attrib,valeur)
# wyświetlana jest nazwa znacznika i ewentualne atrybuty
if precisions :
print "(%s,%s)" % (name,precisions)
else :
print name
# kolejny poziom drzewa
depth+=1
# czy jest to tag danych?
global balisesDonnees,baliseDeDonnees
if balisesDonnees.has_key(name.lower()):
baliseDeDonnees=1
# funkcja wywoływana po napotkaniu znacznika końcowego
def endElement(self,name):
# koniec tagu
# poziom wcięcia
global depth
depth-=1
# sekwencja spacji (wcięcie)
print " " * depth,
# nazwa znacznika
print "/%s" % (name)
# funkcja wyświetlania danych
def characters(self,data):
# dane
global baliseDeDonnees
# czy bieżący tag jest tagiem danych?
if not baliseDeDonnees :
return
# poziom wcięcia
global depth
# ciąg spacji (wcięcie)
print " " * depth,
# dane są wyświetlane
match=re.match(r"^\s*(.*)\s*$",data)
if match:
print "[%s]" % (match.groups()[0])
# koniec znacznika danych
baliseDeDonnees=False
# ------------------------------------------- main
# program
# dane
file="data.xml" # plik xml
depth=0 # poziom wcięcia = głębokość w drzewie
balisesDonnees={"nom":1,"prenom":1,"age":1,"section":1,"formation":1}
baliseDeDonnees=True # wartość „true” oznacza, że mamy do czynienia z tagiem danych
# tworzymy obiekt do analizy tekstu XML
xml_parser=xml.sax.make_parser()
# menedżer tagów
xml_parser.setContentHandler(XmlHandler())
# przetwarzanie pliku XML
xml_parser.parse(file)
Uwagi:
- skrypt korzysta z biblioteki funkcji modułów xml.sax, xml.sax.handler (wiersz 3);
- wiersz 62: analizowany plik XML;
- wiersz 68: parser XML;
- wiersz 70: menedżerem zdarzeń generowanych przez parser będzie instancja klasy XmlHandler;
- wiersz 72: uruchomiono analizę dokumentu XML;
- wiersz 6: klasa implementująca metody startElement, endElement, characters. Jest ona pochodną klasy xml.sax.handler.ContentHandler, która implementuje metody wykorzystywane przez parser;
- wiersz 9: metoda startElement;
- wiersz 30: metoda endElement;
- wiersz 41: metoda characters.
Wyniki są takie same, jak te przedstawione na początku tego akapitu.
