Skip to content

14. Verarbeitung von XML-Dokumenten

  

Betrachten Sie das folgende XML-Dokument:

<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>

Wir analysieren dieses Dokument, um die folgende Konsolenausgabe zu erzeugen:

 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

Wir müssen wissen, wie man Folgendes erkennt:

  • ein Start-Tag wie <training>;
  • ein End-Tag wie z. B. </teacher>;
  • ein Start-Tag mit Attributen wie <person gender="F">;
  • den Inhalt eines Tags, wie z. B. „martin“ in <name>martin</name>.

Ein Programm, das XML-Code analysiert, wird als XML-Parser bezeichnet. Zwei Module stellen die zum Parsen von XML-Code erforderlichen Funktionen bereit: xml.sax und xml.sax.handler.

Das Modul [xml.sax] stellt uns einen XML-Parser zur Verfügung, der mit der folgenden Anweisung aufgerufen wird:

xml_parser=xml.sax.make_parser()

Dieser Parser analysiert den XML-Text sequenziell. Er ruft bei Ereignissen benutzerdefinierte Methoden auf:

  • die Methode startElement bei einem Start-Tag;
  • die Methode endElement bei einem schließenden Tag;
  • die Methode characters beim Hauptteil eines Tags.

Wir müssen dem Parser mitteilen, welche Klasse diese Methoden implementiert:

xml_parser.setContentHandler(XmlHandler())

Wir übergeben eine Instanz einer Klasse, die die Methoden startElement, endElement und characters implementiert, an die Methode setContentHandler des Parsers. Die verwendete Klasse ist eine Unterklasse der Klasse xml.sax.handler.ContentHandler. Die vorgenannten Methoden werden mit Parametern aufgerufen:

def startElement(self,name,attributs):
  • name ist der Name des Start-Tags. attributes ist das Wörterbuch der Attribute des Tags. Für das Tag <person sex="M"> haben wir also name="person" und attributes={'sex':'M'}
def endElement(self,name):
  • name ist der Name des End-Tags. Für das Tag </student> haben wir also name='student'.
def characters(self,data):
  • data ist der Inhalt des Tags. Wenn das Tag also
<nom>
    dupont
</nom>

wir erhalten data='\r\n dupont\r\n '. Im Allgemeinen entfernen wir die Leerzeichen vor und nach den Daten.

Nachdem dies nun erklärt ist, können wir zum Skript zum Parsen eines XML-Dokuments übergehen:


Das Programm (xml_sax_01)

#    -*- coding=utf-8 -*-

import xml.sax, xml.sax.handler,re

#    management class XML
class XmlHandler(xml.sax.handler.ContentHandler):

    #  function called when a start tag is encountered
    def startElement(self,name,attributs):
        global depth
        #    a sequence of spaces (indentation)
        print " " * depth,
        #    attributes
        precisions=""
        for (attrib,valeur) in attributs.items():
            precisions+="(%s,%s) " % (attrib,valeur)
        #  displays the tag name and any attributes
        if precisions :
            print "(%s,%s)" % (name,precisions)
        else :
            print name
        #    an extra level of tree structure
        depth+=1
        #  is it a data tag?
        global balisesDonnees,baliseDeDonnees
        if balisesDonnees.has_key(name.lower()):
            baliseDeDonnees=1

    #  the function called when an end tag is encountered
    def endElement(self,name):
        #    end of tag
        #    indentation level
        global depth
        depth-=1
        #    a sequence of spaces (indentation)
        print " " * depth,
        #    tag name
        print "/%s" % (name)

    #    data display function
    def characters(self,data):
        #    data
        global baliseDeDonnees

        #  is the current tag a data tag?
        if not baliseDeDonnees :
            return
        #    indentation level
        global depth
        #    a sequence of spaces (indentation)
        print " " * depth,
        #  data are displayed
        match=re.match(r"^\s*(.*)\s*$",data)
        if match:
            print "[%s]" % (match.groups()[0])
        #    end of data tag
        baliseDeDonnees=False

#    ------------------------------------------- main  
#  the program
#    data
file="data.xml"       #  the xml file
depth=0               #  indentation level=depth in tree structure
balisesDonnees={"nom":1,"prenom":1,"age":1,"section":1,"formation":1}
baliseDeDonnees=True     #    to true, indicates a data tag

#    create an xml text analysis object
xml_parser=xml.sax.make_parser()
#  the tag manager
xml_parser.setContentHandler(XmlHandler())
#    xml file processing
xml_parser.parse(file)

Hinweise:

  • Das Skript verwendet die Funktionsbibliothek aus den Modulen xml.sax und xml.sax.handler (Zeile 3);
  • Zeile 62: die geparste XML-Datei;
  • Zeile 68: der XML-Parser;
  • Zeile 70: Der Handler für vom Parser ausgegebene Ereignisse ist eine Instanz der Klasse XmlHandler;
  • Zeile 72: Das Parsen des XML-Dokuments beginnt;
  • Zeile 6: die Klasse, die die Methoden startElement, endElement und characters implementiert. Sie ist von der Klasse xml.sax.handler.ContentHandler abgeleitet, die vom Parser verwendete Methoden implementiert;
  • Zeile 9: die Methode „startElement“;
  • Zeile 30: die Methode „endElement“;
  • Zeile 41: die Methode *characters.*

Die Ergebnisse sind die am Anfang dieses Absatzes dargestellten.