Skip to content

14. Belge işleme XML

  

Aşağıdaki XML belgesini ele alalım:

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

Bu belgeyi analiz ederek aşağıdaki konsol çıktısını elde ediyoruz:

 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

Şunları nasıl tanıyacağımızı bilmeliyiz:

  • <eğitim> gibi bir başlangıç etiketini;
  • </enseignant> gibi bir bitiş etiketini;
  • <personne sexe="F"> gibi öznitelikli bir başlangıç etiketini;
  • martin gibi bir etiket gövdesi (<nom>martin</nom>. içinde)

XML kodunu analiz eden programa XML ayrıştırıcısı denir. XML kodunu ayrıştırmak için gerekli işlevleri bize iki modül sağlar: xml.sax ve xml.sax.handler.

[xml.sax] modülü, şu komut aracılığıyla bize bir XML ayrıştırıcısı sağlar:

xml_parser=xml.sax.make_parser()

Bu ayrıştırıcı, XML metnini sırayla analiz eder. Aşağıdaki olaylarda kullanıcı yöntemlerini çağırır:

  • etiket başlangıcında startElement yöntemi;
  • etiket sonu durumunda endElement yöntemi;
  • characters yöntemi, bir etiket gövdesi üzerinde.

Ayrıştırıcıya, bu yöntemleri uygulayan sınıfı belirtmemiz gerekir:

xml_parser.setContentHandler(XmlHandler())

Ayrıştırıcının setContentHandler yöntemine, startElement, endElement ve characters yöntemlerini uygulayan bir sınıf örneği aktarıyoruz. Kullanılan sınıf, xml.sax.handler.ContentHandler sınıfından türetilmiş bir sınıftır. Yukarıdaki yöntemler aşağıdaki parametrelerle çağrılır:

def startElement(self,name,attributs):
  • name, başlangıç etiketinin adıdır. attributs ise etiketin öznitelik sözlüğüdür. Dolayısıyla, <personne sexe="M"> etiketi için name="personne" ve attributs={'sexe':'M'} değerleri elde edilir.
def endElement(self,name):
  • name, bitiş etiketinin adıdır. Dolayısıyla, </etudiant> etiketi için name='etudiant' olacaktır.
def characters(self,data):
  • data, etiket gövdesidir. Dolayısıyla, etiket
<nom>
    dupont
</nom>

data='\r\n dupont\r\n ' elde ederiz. Genellikle, verinin başındaki ve sonundaki boşluklar kaldırılır.

Bunu açıkladıktan sonra, XML formatındaki bir belgeyi analiz eden komut dosyasına geçebiliriz:


Program (xml_sax_01)


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

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

# yönetim sınıfı XML
class XmlHandler(xml.sax.handler.ContentHandler):

    # başlangıç etiketiyle karşılaşıldığında çağrılan işlev
    def startElement(self,name,attributs):
        global depth
        # bir dizi boşluk (girinti)
        print " " * depth,
        # öznitelikler
        precisions=""
        for (attrib,valeur) in attributs.items():
            precisions+="(%s,%s) " % (attrib,valeur)
        # etiket adı ve varsa öznitelikler görüntülenir
        if precisions :
            print "(%s,%s)" % (name,precisions)
        else :
            print name
        # bir üst düzey daha
        depth+=1
        # bu bir veri etiketi mi?
        global balisesDonnees,baliseDeDonnees
        if balisesDonnees.has_key(name.lower()):
            baliseDeDonnees=1

    # son etiketine rastlandığında çağrılan işlev
    def endElement(self,name):
        # etiket sonu
        # girinti düzeyi
        global depth
        depth-=1
        # bir dizi boşluk (girinti)
        print " " * depth,
        # etiket adı
        print "/%s" % (name)

    # veri görüntüleme işlevi
    def characters(self,data):
        # veriler
        global baliseDeDonnees

        # geçerli etiket bir veri etiketi mi?
        if not baliseDeDonnees :
            return
        # girinti düzeyi
        global depth
        # bir dizi boşluk (girinti)
        print " " * depth,
        # veriler görüntüleniyor
        match=re.match(r"^\s*(.*)\s*$",data)
        if match:
            print "[%s]" % (match.groups()[0])
        # veri etiketinin sonu
        baliseDeDonnees=False

# ------------------------------------------- ana  
# program
# veriler
file="data.xml"       # xml dosyası
depth=0               # girinti seviyesi=ağaç yapısındaki derinlik
balisesDonnees={"nom":1,"prenom":1,"age":1,"section":1,"formation":1}
baliseDeDonnees=True     # "true" ise, bir veri etiketiyle karşı karşıya olduğumuzu gösterir

# bir XML metin analiz nesnesi oluşturulur
xml_parser=xml.sax.make_parser()
# etiket yöneticisi
xml_parser.setContentHandler(XmlHandler())
# XML dosyasının işlenmesi
xml_parser.parse(file)

Notlar:

  • komut dosyası, xml.sax ve xml.sax.handler modüllerinin işlev kütüphanesini kullanır (3. satır);
    1. satır: analiz edilen XML dosyası;
    1. satır: XML ayrıştırıcısı;
  • satır 70: ayrıştırıcı tarafından gönderilen olayların yöneticisi, XmlHandler sınıfının bir örneği olacaktır;
  • satır 72: XML belgesinin analizi başlatılır;
    1. satır: startElement, endElement ve characters yöntemlerini uygulayan sınıf. Bu sınıf, ayrıştırıcı tarafından kullanılan yöntemleri uygulayan xml.sax.handler.ContentHandler sınıfından türetilmiştir;
    1. satır: startElement yöntemi;
    1. satır: endElement yöntemi;
    1. satır: characters. yöntemi

Sonuçlar, bu paragrafın başında sunulanlarla aynıdır.