14. Processamento de documentos XML
![]() |
Consideremos o seguinte documento 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>
Analisamos este documento para produzir a seguinte saída na consola:
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
Temos de saber como reconhecer:
- uma baliza de início, como <formação>;
- uma baliza de fim, como </enseignant>;
- uma baliza de início com atributos, como <pessoa sexo="F">;
- o corpo de uma baliza como martin em <nom>martin</nom>.
O programa de análise de um código XML é denominado analisador XML. Dois módulos fornecem-nos as funcionalidades para analisar um código XML: xml.sax e xml.sax.handler.
O módulo [xml.sax] fornece-nos um analisador XML através da instrução:
Este analisador analisa o texto XML sequencialmente. Chama métodos do utilizador em eventos:
- o método startElement ao início de uma baliza;
- o método endElement ao encontrar o fim de uma baliza;
- o método characters no corpo de uma baliza.
Temos de indicar ao analisador a classe que implementa estes métodos:
Passamos ao método setContentHandler do analisador uma instância da classe que implementa os métodos startElement, endElement e characters. A classe utilizada é uma classe derivada da classe xml.sax.handler.ContentHandler. Os métodos anteriores são chamados com os seguintes parâmetros:
- name é o nome da baliza de início. attributs é o dicionário de atributos da baliza. Assim, para a baliza <pessoa sexo="M">, teremos name="personne" e attributs={'sexe':'M'}
- name é o nome da baliza de fim. Assim, para a baliza </etudiant>, teremos name='etudiant'.
- data é o corpo da baliza. Assim, se a baliza for
teremos data='\r\n dupont\r\n '. Em geral, eliminam-se os espaços que precedem e seguem os dados.
Dito isto, podemos passar ao script de análise de um documento XML:
# -*- coding=utf-8 -*-
import xml.sax, xml.sax.handler,re
# classe de gestão XML
class XmlHandler(xml.sax.handler.ContentHandler):
# função chamada ao encontrar uma baliza de início
def startElement(self,name,attributs):
global depth
# uma sequência de espaços (indentação)
print " " * depth,
# atributos
precisions=""
for (attrib,valeur) in attributs.items():
precisions+="(%s,%s) " % (attrib,valeur)
# exibe-se o nome da baliza e os eventuais atributos
if precisions :
print "(%s,%s)" % (name,precisions)
else :
print name
# mais um nível na árvore
depth+=1
# trata-se de uma baliza de dados?
global balisesDonnees,baliseDeDonnees
if balisesDonnees.has_key(name.lower()):
baliseDeDonnees=1
# a função chamada quando se encontra uma baliza de fim
def endElement(self,name):
# fim da baliza
# nível de indentação
global depth
depth-=1
# uma sequência de espaços (indentação)
print " " * depth,
# o nome da baliza
print "/%s" % (name)
# a função de exibição dos dados
def characters(self,data):
# dados
global baliseDeDonnees
# a tag atual é uma tag de dados?
if not baliseDeDonnees :
return
# nível de indentação
global depth
# uma sequência de espaços (indentação)
print " " * depth,
# os dados são apresentados
match=re.match(r"^\s*(.*)\s*$",data)
if match:
print "[%s]" % (match.groups()[0])
# fim da baliza de dados
baliseDeDonnees=False
# ------------------------------------------- main
# o programa
# dados
file="data.xml" # o ficheiro XML
depth=0 # nível de indentação = profundidade na árvore
balisesDonnees={"nom":1,"prenom":1,"age":1,"section":1,"formation":1}
baliseDeDonnees=True # se for verdadeiro, indica que se trata de uma baliza de dados
# cria-se um objeto de análise de texto XML
xml_parser=xml.sax.make_parser()
# o gestor de tags
xml_parser.setContentHandler(XmlHandler())
# análise do ficheiro XML
xml_parser.parse(file)
Notas:
- o script utiliza a biblioteca de funções dos módulos xml.sax e xml.sax.handler (linha 3);
- linha 62: o ficheiro XML analisado;
- linha 68: o analisador XML;
- linha 70: o gestor de eventos emitidos pelo analisador será uma instância da classe XmlHandler;
- linha 72: é iniciada a análise do documento XML;
- linha 6: a classe que implementa os métodos startElement, endElement, characters. Esta é derivada da classe xml.sax.handler.ContentHandler, que implementa métodos utilizados pelo analisador;
- linha 9: o método startElement;
- linha 30: o método endElement;
- linha 41: o método characters.
Os resultados são os apresentados no início deste parágrafo.
