E.6.3 Paket SGML (p_sgml.py)

# -------------------------------------------------------------
# Projekt : Digitale Bibliotheken Projekt
# Uni-Frankfurt/M, Professur Telematik und
# verteilte Systeme, Prof. O. Drobnik
# Diplomarbeit, Matzen,Hans, 1997
#
# Dateiname : p_sgml.py
# Datum : 03.11.1997
# letzte Änderung :
# Autor : Hans Matzen, 1997, Frankfurt/M, Deutschland
# Sprache : Python v1.4
# Beschreibung : Paket SGML, fasst alle SGML-Paket Klassen
# zusammen
#
# Anmerkungen :
#
# -------------------------------------------------------------
import c_sgmlquery
import c_sgmlread
import c_sgmlsearch
import c_sgmlstore
 
Klasse c_sgmlquery
# -------------------------------------------------------------
# Projekt : Digitale Bibliotheken Projekt
# Uni-Frankfurt/M, Professur Telematik und
# verteilte Systeme, Prof. O. Drobnik
# Diplomarbeit, Matzen,Hans, 1998
# Dateiname : c_sgmlquery.py
# Datum : 09.12.1997
# letzte Änderung :
# Autor : Hans Matzen, 1997, Frankfurt/M, Deutschland
# Sprache : Python v1.4
# Beschreibung : Eine Klasse die SGML spezifische Abfragen auf
# einem bestimmten Dokument durchfuehrt.
# Anmerkungen :
# -------------------------------------------------------------
 
# imports
from sc_globals import *
import pgpy
 
class c_sgmlquery:
    #
    # Konstruktor
    #
    def __init__(self,ident):
        self.ident=ident
        # Datenbankverbindungsobjekt instanziieren
        self.pgconn=pgpy.pgconn(DL_PGHOST,DL_PGPORT,DL_DBNAME)
         
    #
    # liefert das tagcount'e Tag mit Namen tagname zurueck
    #
    def sgmlquery_tag(self,tagname,tagcount):
        query="select * from doc_tags where docnr="+str(self.ident)
        query=query + " and contents ~* '"+tagname+"*' order by elementnr;"
             
        res=self.pgconn.exec_query(query)
        if res.get_tuple_count()>0:
            return [ res.get_fieldvalue(tagcount-1,res.get_fieldindex_byname("contents")),res.get_fieldvalue(tagcount-1,res.get_fieldindex_byname("elementnr")) ]
        else:
            return ["",0]
    #
    # liefert den Inhalt des tagcount'en Tags
    # mit Namen tagname zurueck
    #
    def sgmlquery_tagcontents(self,tagname,tagcount):
        pos1=self.sgmlquery_tag(tagname,tagcount)[1]
        query1="select contents,elementnr from doc_tags where docnr="+str(self.ident)
        query1=query1 + " and elementnr>"+str(pos1)
        query1=query1 +"and contents ~* '</"+tagname+"' order by elementnr;"
        res1=self.pgconn.exec_query(query1)
        if res1.get_tuple_count>0:
            pos2=res1.get_fieldvalue(0,1)
 
            query2= "select contents,elementnr from doc_elements* where docnr="
            +str(self.ident)
            query2=query2+" and elementnr>="+str(pos1)
            query2=query2+" and elementnr<="+str(pos2)+" order by elementnr;"
             
            res2=self.pgconn.exec_query(query2)
            if res2.get_tuple_count>0:
                j=res2.get_tuple_count()
                i=0
                erg=""
                while i < j:
                    erg=erg+str(res2.get_fieldvalue(i,0))+"\n"
                    i=i+1
                         
                return erg[:-1]
            else:
                return ""
        else:
            return ""
 
    #
    # liefert den Strukturbaum als ASCII Text zurueck
    #
    def sgmlquery_structure(self):
        query="select contents,elementnr from doc_tags where docnr="+ str(self.ident) + " order by elementnr;"
 
        res=self.pgconn.exec_query(query)
        j=res.get_tuple_count()
        i=0
        erg=""
        while i < j:
            erg=erg+str(res.get_fieldvalue(i,0))+"\n"
            i=i+1
        return erg[:-1]
             
    #
    # gibt das gesamte Dokument zurueck
    #
    def sgmlquery_doc(self):
        query="select contents,elementnr from doc_elements* where docnr="+str(self.ident)+" order by elementnr;"
             
        res=self.pgconn.exec_query(query)
        j=res.get_tuple_count()
        i=0
        erg=""
        while i < j:
            erg=erg+str(res.get_fieldvalue(i,0))+"\n"
            i=i+1
        return erg
 
    #
    # gibt die Anzahl der Tags mit Namen tagname zurueck
    #
    def sgmlquery_tagcount(self,tagname):
        query="select contents from doc_tags where docnr="+str(self.ident)+" and contents ~* '"+tagname+"';"
        res=self.pgconn.exec_query(query)
        return res.get_tuple_count()
 
    #
    # teilt ein gegebenes Tag (tagstr) in den Tagnamen
    # und die einzelnen Attribute auf und liefert ein
    # Dictionaries zurueck, dessen Schluessel die Attributnamen
    # sind.
    #
    def sgmlquery_splittag(self,tagstr):
        import string
         
        ergdict={}
        t=""
        for j in range(len(tagstr)):
            if tagstr[j]!="\012":
                t=t+tagstr[j]
 
        tagstr=t
 
        # tagklammern entfernen
        tagstr=tagstr[1:-1]
             
        #hole tagname
        pos=string.find(tagstr," ")
        tag=tagstr[:pos]
        tagstr=tagstr[pos:]
 
        # tagname in dictionary einfuegen
        ergdict["TAG"]=tag
 
        #hole attribute
        while len(tagstr)!=0:
         
            # whitespace entfernen
            tagstr=string.strip(tagstr)
 
            # attributname holen
            pos1 = string.find(tagstr,"=")
            attrib = string.strip( tagstr[:pos1] )
            tagstr = tagstr[pos1+1:]
 
            # whitespace entfernen
            tagstr=string.strip(tagstr)
 
            # hole werte
            if len(tagstr)>0:
                if tagstr[0]=="\"":
                    tagstr=tagstr[1:]
                    pos3 = string.find(tagstr,"\"")
                else:
                    pos3 = string.find(tagstr," ")
            else:
                pos3 = string.find(tagstr," ")
  
            if pos3 == -1:
                pos3=len(tagstr)
            wert = string.strip( tagstr[:pos3] )
                 
            tagstr = tagstr[pos3+1:]
 
            # attribute werte paar in dictionary einfuegen
            ergdict[attrib]=wert
 
        return ergdict
 
 
 
Klasse c_sgmlsearch
# -------------------------------------------------------------
# Projekt : Digitale Bibliotheken Projekt
# Uni-Frankfurt/M, Professur Telematik und
# verteilte Systeme, Prof. O. Drobnik
# Diplomarbeit, Matzen,Hans, 1998
# Dateiname : c_sgmlsearch.py
# Datum : 09.12.1997
# letzte Änderung : 15.01.1998
# Autor : Hans Matzen, 1997, Frankfurt/M, Deutschland
# Sprache : Python v1.4
# Beschreibung : Dies Klasse realisiert ein Suchinterface fuer
# in der Datenbank abgelegte SGML Dokumente
# Anmerkungen :
#
# -------------------------------------------------------------
 
# imports
import pgpy
 
class c_sgmlsearch:
    #
    # Konstruktor
    #
    def __init__(self):
        # Verbindungsobjekt zur Datenbank instanziieren
        self.conn=pgpy.pgconn(DL_PGHOST,DL_PGPORT,DL_DBNAME)
 
    #
    # Durchsucht alle in der Datenbank gespeicherten
    # Tags nach searchstr und findet auch aehnliche
    # Ausdruecke.
    # Als Ergebnis wird eine ASCII Liste von Dokumenten ID's
    # zurueckgegeben
    #
    def sgmlsearch_tag(self,searchstr):
        # SQL Abfrage zusammenbauen
        query="select * from doc_tags where contents ~*"+searchstr+";"
        # Abfrage ausfuehren
        res=self.conn.exec_query(query)
        # Fehler aufgetreten ?
        if res.get_tuple_count()==0:
            # wenn ja, -1 zurueckgeben
            return -1
        else:
            #wenn nein Ergebnis zurueckgeben
            erg=res.get_resultlist(1,"|",1,0)
            return erg
 
    #
    # Durchsucht die Text Klasse der Datenbank
    # nach searchstr und findet auch aehnliche
    # Ausdruecke.
    # Als Ergebnis wird eine ASCII Liste von Dokumenten ID's
    # zurueckgegeben
    #
    def sgmlsearch_text(self,searchstr):
        # SQL Abfrage zusammenbauen
        query="select * from doc_text where contents ~*"+searchstr+";"
        # Abfrage ausfuehren
        res=self.conn.exec_query(query)
        # Fehler aufgetreten ?
        if res.get_tuple_count()==0:
            # wenn ja, -1 zurueckgeben
            return -1
        else:
            #wenn nein Ergebnis zurueckgeben
            erg=res.get_resultlist(1,"|",1,0)
            return erg
 
    #
    # virtuelle Methode, muss in einer abgeleiteten
    # Klasse ueberschrieben werden und ist zum Durchsuchen
    # von Binaerdaten gedacht ;-)
    #
    def sgmlsearch_bin(self):
                pass
     
    #
    # Durchsucht die Tag- und die Text- Klasse der Datenbank
    # nach searchstr und findet auch aehnliche
    # Ausdruecke.
    # Als Ergebnis wird eine ASCII Liste von Dokumenten ID's
    # zurueckgegeben.
    #
    def sgmlsearch_doc(self,searchstr):
        erg=[]
        erg1=self.sgmlsearch_tag(searchstr)
        erg2=self.sgmlsearch_text(searchstr)
        if erg1!=-1:
            erg.append(erg1)
        if erg2!=-1:
            erg.append(erg2)
        return erg
 
    #
    # ermittelt die Dokumenten-ID`s aller Dokumente, die der
    # in dtdid gegebenen DTD entsprechen. Dabei kann dtdid
    # die Public- oder die System-ID einer DTD angeben.
    # Das Ergebnis wird in Form einer Lsite zurueckgeliefert.
    #
    def sgmlsearch_dtddocs(self,dtdid):
        # DTD-Nummer ermitteln
        query="select dtdnr from dtd where publicname ="+ dtdid + "or systemname =" +dtdid+";"
        # Abfrage ausfuehren
        res=self.conn.exec_query(query)
        # Fehler aufgetreten ?
        if res.get_tuple_count()==0:
            # wenn ja, -1 zurueckgeben
            return []
        else:
            #wenn nein Ergebnis zurueckgeben
            dtdnr=res.get_fieldvalue(1,0)
 
        # Doc-ID`s holen
        query="select docnr from doc_description where dtdnr=" + str(dtdnr)+";"
        # Abfrage ausfuehren
        res=self.conn.exec_query(query)
        # Fehler aufgetreten ?
        if res.get_tuple_count()==0:
            # wenn ja, -1 zurueckgeben
            return []
        else:
            #wenn nein Ergebnis zurueckgeben
            erg=res.get_resultlist(1,"|",1,0)
            return erg
    #
    # ermittelt die Dokumenten-ID`s aller Dokumente, die
    # der durch dtdid gegebenen DTD entsprechen und ein Tag
    # enthalten das searchstr entspricht. Das Ergebnis wird
    # in Form einer Liste zurueckgegeben.
    #
    def sgmlsearch_dtdandtags(self,dtdid,searchstr):
        # ermittle Teilergebnisse
        erg1=self.sgmlsearch_tag(searchstr)
        erg2=self.sgmlsearch_dtddocs(dtdid)
         
        erg=[]
        for i in erg1:
            if i in erg2:
                erg.append(i)
 
        return erg
 
Klasse c_sgmlstore
# -------------------------------------------------------------
# Projekt : Digitale Bibliotheken Projekt
# Uni-Frankfurt/M, Professur Telematik und
# verteilte Systeme, Prof. O. Drobnik
# Diplomarbeit, Matzen,Hans, 1998
# Dateiname : c_sgmlstore.py
# Datum : 09.12.1997
# letzte Änderung :
# Autor : Hans Matzen, 1997, Frankfurt/M, Deutschland
# Sprache : Python v1.4
# Beschreibung : Diese Klasse stellt Methoden bereit, um als
# Bitstrom vorliegende SGML-Dokumente in der
# Datenbank zu speichern
# Anmerkungen : Diese Klasse wird von der Klasse c_sgmlread
# abgeleitet. Die Varibalen DL_CURRENT_INFILE
# und DL_NEW_DOCID werden von der Ablauf-
# umgebung gesetzt.
# -------------------------------------------------------------
 
# imports
from sc_globals import *
import class_funcs
import pgpy
import c_sgmlread
import urllib
import regsub
 
 
class c_sgmlstore(c_sgmlread.c_sgmlread):
    # Variablen
    infile=""
    docid=0
    fd_in=0
    emptytags=[]
    dtdfname=""
    # Variablen fuer Strukturbaumberechnungen
    atag,ntag,atyp,ntyp="","","",""
    anum=0
    nnum=0
    stack=[]
    element_counter=0
    ls=("",0)
     
 
    #
    # Konstruktor
    #
    def __init__(self,DL_CURRENT_INFILE,DL_NEW_DOCID):
        # uebernehme Parameter
        self.infile=DL_CURRENT_INFILE
        self.docid=DL_NEW_DOCID
         
        # Konstruktur der Basisklasse
        c_sgmlread.c_sgmlread.__init__(self,self.infile)
         
        # hole Liste der EMPTY Tags
        self.dtdfname=class_funcs.get_dtdfile(self.get_dtd())
        self.emptytags_lst=self.get_emptytags(self.dtdfname)
         
        # baue Verbindung zu Postgres auf
        self.conn=pgpy.pgconn(DL_PGHOST,DL_PGPORT,DL_DBNAME)
        if self.conn.connstatus()!=0:
            print "Postgresverbindung konnte nicht aufgebaut werden."
            raise KeyboardInterrupt
             
    #
    # oeffnet den eingabebitstrom
    #
    def open_in(self):
        self.fd_in=open(self.infile,"r")
    #
    # schliesst den Eingabebitstrom
    #
    def close_in(self):
        self.fd_in.close()
    #
    # liest size Bytes vom Eingabebitstrom
    #
    def read_in(self,size):
        return self.fd_in.read(size)
     
    #
    # setzt die aktuelle Position der Lese-/Schreibmarke
    # des Eingabebitstroms (Syntax wie Python Befehl seek)
    #
    #
    def seek_in(self,offset,whence):
        self.fd_in.seek(offset,whence)
 
    #
    # liefert die aktuelle Position der Lese-/Schreibmarke
    # des Eingabebitstroms zurueck
    #
    def tell_in(self):
        return self.fd_in.tell()
 
    #
    # filtert in der Datenbank abzulegende Text, um sie an
    # die PostgreSQL Syntax anzupassen
    #
    def pgfilter(self,fstr):
        erg=""
        for i in range(0,len(fstr)):
            # ersetze anfuehrungszeichen
            if fstr[i]=="'":
                erg=erg+"\\"
                         
            erg=erg+fstr[i]
        return erg
 
 
    #
    # liefert eine Liste alle in der DTD fname definierten
    # EMPTY-Tags zurueck
    #
    def get_emptytags(self,fname):
        import c_bsio
        import string
 
        fd=c_bsio.c_bsio(fname,"r")
        erglst=[]
        fd.open()
        buff = " "
        while buff!="":
            buff=fd.readline()
            if string.upper(string.strip(buff)[:9])=="<!ELEMENT":
                if string.find(buff,"EMPTY")!=-1:
                    erglst.append(string.upper( string.strip(buff)[10:string.find( string.strip(buff),"-")-1]))
        fd.close()
        return erglst
 
 
    #
    # vermerkt in der Datenbank, dass das Dokument in der Datenbank
    # gespeichert wurde
    #
    def register_sgmlstore(self):
        query="update doc_description set sgml_stored='t' where docnr="
        query=query+str(self.docid)+";"
        res=self.conn.exec_query(query)
        if res.commandstatus()[0:6]!="UPDATE":
            print "Fehler bei Update in register_sgmlstore"
            return -1
        else:
            return 0
 
    #
    # vermerkt die DTD der das Dokument angehoerig ist in
    # der Datenbank
    #
    def save_doctype(self):
        dtdtup=self.get_dtd()
        dtdnum=class_funcs.get_dtdnum(dtdtup)
             
        query="update doc_description set dtdnr="
        query=query+str(res.get_fieldvalue(1,0))
        query=query+" where docnr="+str(self.docid)+";"
             
        res=self.conn.exec_query(query)
        if res.commandstatus[0:6]!="UPDATE":
            print "Fehler c_sgmlstore.save_doctype beim Eintragen der DTDNR"
    #
    # speichert tagst in der Tag-Klasse der Datenbank
    # und berechnet die Strukturbaumverweise automatisch
    #
    def save_astag(self,tagstr):
        dbclass="doc_tags"
        self.element_counter=self.element_counter+1
 
        self.nnum=self.element_counter
        self.ntag=tagstr
        isempty=self.is_emptytag(self.ntag)
        # Berechnungen fuer Strukturbaum
 
        if self.ntag[0:2]!="</":
            self.ntyp="S"
            self.stack.append((self.ntag,self.nnum))
        else:
            self.ntyp="E"
            self.ls=self.stack[-1]
            self.stack=self.stack[:-1]
 
        if self.ntyp=="S" and self.atyp=="S":
            # atag ist Vater von ntag
            query="update doc_tags set son="+str(self.nnum)
            query=query+" where docnr="+str(self.docid)
            query=query+" and elementnr="+str(self.anum)+";"
 
            res=self.conn.exec_query(query)
            if res.commandstatus()[0:6]!="UPDATE":
               print "FEHLER in c_sgmlstore.save_astag Query 1"
 
        if self.ntyp=="S" and self.atyp=="E":
            # ntag ist rechter Bruder von anum
            query="update doc_tags set brother="+str(self.nnum)
            query=query+" where docnr="+str(self.docid)
            query=query+" and elementnr="+str(self.anum)+";"
 
            res=self.conn.exec_query(query)
            if res.commandstatus()[0:6]!="UPDATE":
                print "FEHLER in c_sgmlstore.save_astag Query 2"
 
        if self.ntyp=="E" and self.atyp=="S":
            # atag ist ein Blatt
            query="update doc_tags set brother="+str(self.nnum)
            query=query+" where docnr="+str(self.docid)
            query=query+" and elementnr="+str(self.anum)+";"
 
            res=self.conn.exec_query(query)
            if res.commandstatus()[0:6]!="UPDATE":
                print "FEHLER in c_sgmlstore.save_astag Query 3"
 
        if self.ntyp=="E" and self.atyp=="E":
            # atag ist ein Blatt
            query="update doc_tags set brother="+str(self.nnum)
            query=query+" where docnr="+str(self.docid)
            query=query+" and elementnr="+str(self.ls[1])+";"
 
            res=self.conn.exec_query(query)
            if res.commandstatus()[0:6]!="UPDATE":
                print "FEHLER in c_sgmlstore.save_astag Query 4"
 
 
        # letztes Tag und Typ merken
        self.atag=self.ntag
        self.anum=self.nnum
        if isempty==0:
            self.atyp=self.ntyp
        elif isempty==1:
            self.atyp="E"
            self.stack=self.stack[:-1]
 
        # neuen Tagdatensatz in DB eintragen
        tagstr=self.pgfilter(tagstr)
        query="insert into "+dbclass+" values ("+str(self.docid)+","
        query=query+str(self.nnum)+",0,0,'"+tagstr+"',"
        query=query+str(0)+");"
 
        res=self.conn.exec_query(query)
        if res.commandstatus()[0:6]!="INSERT":
            print "FEHLER in c_sgmlstore.save_astag Query 5"
 
    #
    # speichert textstr in der Text-Klasse der Datenbank
    #
    def save_astext(self,textstr):
        dbclass="doc_text"
        self.element_counter=self.element_counter+1
        textstr=self.pgfilter(textstr)
        query="insert into "+dbclass+" values ("+str(self.docid)+","
        query=query+str(self.element_counter)+",0,0,'"+textstr+"');"
         
        res=self.conn.exec_query(query)
        erg=res.commandstatus()
        if str(erg)[0:6]!="INSERT":
            print "Fehler bei INSERT in Postgres"
            raise KeyboardInterrupt
        return 0
    #
    # speichert das unter der URL urlstr abrufbare Objekt
    # als binaere Daten in der Datenbank
    #
    def save_asbin(self,urlstr):
        dbclass="doc_bin"
        self.element_counter=self.element_counter+1
        binstr=urllib.urlretrieve(urlstr)
        query="insert into "+dbclass+" values ("+str(self.docid)+","
        query=query+str(self.element_counter)+",0,0,'"+binstream+"');"
             
        res=self.conn.exec_query(query)
        erg=res.commandstatus()
        if str(erg)[0:6]!="INSERT":
            print "Fehler bei INSERT in Postgres"
            raise KeyboardInterrupt
        return 0
    #
    # liest das naechste Tag aus dem Eingabebitstrom und
    # gibt es zurueck
    #
    def get_nextelement(self):
        # leerzeilen ueberspringen
        test1=""
        test1=self.read(1)
        while test1=="\n":
            test1=self.read(1)
         
        # position des Lese-/Schreibmarke korrigieren
        if test1!="":
            if self.tell()>1:
                self.seek(-1,1)
 
            # sicherstellen das nicht mitten im Tag gesucht wird
            if test1=="<":
                return self.get_nexttag()
            else:
                erg=""
                buff=" "
                while buff!="<" and buff!="":
                    buff=self.read(1)
                    erg=erg+buff
         
                # letztes Zeichen wegwerfen
                if len(erg)>1:
                    erg=erg[0:-1]
                # position des Lese-/Schreibmarke korrigieren
                self.seek(-1,1)
                return erg
        else:
            return ""
    #
    # ermittelt, ob es sich bei tagstr um ein Tag handelt
    # gibt 1 zureuck wenn ja, 0 wenn nein und -1 bei Fehler
    #
    def is_tag(self,tagstr):
        if len(tagstr)!=0:
            if tagstr[0]=="<" and tagstr[len(tagstr)-1]==">":
                return 1
            else:
                return 0
        else:
            return -1
    #
    # ermittelt, ob es sich bei tagstr um ein Empty-Tag handelt
    # gibt 1 zureuck wenn ja, 0 wenn nein und -1 bei Fehler
    #
    def is_emptytag(self,tagstr):
        import string
        if len(tagstr)!=0:
            if tagstr[1:string.find(tagstr," ")] in self.emptytags_lst:
                return 1
            else:
                return 0
        else:
            return -1