2.2 Speichern von SGML-Dokumenten

Das Speichern von SGML-Dokumenten kann in vielfältiger Weise geschehen. Im folgenden sollen einige repräsentative Verfahren erläutert werden.

Man speichert bzw. archiviert Dokumente, weil man zu einem späteren Zeitpunkt wieder darauf zugreifen möchte. Die Art des Zugriffs resultiert im wesentlichen aus der Art, auf die das Dokument gespeichert wurde. Um komfortabel auf SGML-Dokumente zugreifen zu können, benutzt man Kenntnisse über die Struktur des Dokuments bereits beim Speichern. Diese Kenntnisse werden entweder aus der DTD, aus dem SGML-Dokument selbst oder aus beiden gewonnen. In allen Fällen versucht man das Wissen über den strukturellen Aufbau der SGML-Dokumente zu nutzen, um später effizienter und effektiver darauf zugreifen zu können.

Die verschiedenen Methoden ein SGML-Dokument zu speichern bieten verschiedene Möglichkeiten auf den SGML-Dokumenten zu operieren. Im allgemeinen unterscheidet man zwischen Operationen, die Kenntnis über den strukturellen Aufbau des Dokuments haben (strukturorientierte Operationen) und solchen, die ohne jegliche Kenntnis über die Struktur operieren (strukturunabhängige Operationen). Erstere operieren meist effizienter auf den Dokumenten, während zweitere meist mit wesentlich weniger Aufwand zu realisieren sind.

Ein wichtiges Merkmal eines SGML-Dokuments ist der Strukturbaum. Der Strukturbaum stellt die Tag-Hierarchie des Dokuments dar. Er wird benutzt, um ein SGML-Dokument darzustellen oder nur bestimmte Abschnitte zu bearbeiten. Exemplarisch wird der Strukturbaum des in Abbildung 2.2 gezeigten SGML-Dokuments in Abbildung 2.4 dargestellt.


PIC
Abbildung 2.4: Der Strukturbaum des Beispiels

Der Strukturbaum beinhaltet nur den Markup des SGML-Dokuments, nicht aber die von den Tags eingeschlossenen Daten.

Grundsätzlich wird zwischen Markup und Daten unterschieden, mit Daten sind z.B. Texte, binäre Bilddaten, Tondaten, usw. gemeint. Unter einem Bitstrom versteht man eine Menge von Informationen, die bit- oder byteorientiert, z.B. als Datei auf einem Massenspeicher abgelegt sind. Mit Klassen sind die Dateien in einer Datenbank bezeichnet. Dieser Terminus kommt aus der Welt der objekt-orientierten Datenbanken (ODBMS), dort werden Datenstrukturen als Klassen bezeichnet.

2.2.1 Speichern als Bitstrom

Die einfachste Methode ein SGML-Dokument zu speichern, besteht darin, es als Bitstrom in einem Massenspeicher abzulegen. Bei der Speicherung selbst werden keine Eigenschaften des Dokuments berücksichtigt. Will man die so gespeicherten Dokumente durchsuchen oder verändern, so müssen sie sequentiell durchlaufen werden. Zur Unterstützung beim Durchsuchen großer Mengen auf diese Weise aufbewahrter Dokumente gibt es sogenannte SGML-Indizierer. Diese Programme erstellen vorab verschiedene Indizes (z.B. Hashtable, B-Tree), die es erlauben effizient strukturorientiert in den Dokumenten zu suchen. Alternativ stehen zur strukturunabhängigen Suche in Dokumenten sogenannte Volltextindizierer zur Verfügung. Diese ermöglichen die Suche nach Textmustern in einer Menge von Dokumenten, wobei es unerheblich ist, ob diese strukturiert sind oder nicht.

2.2.2 Ein objektorientierter Ansatz, VODAK

Ein objekt-orientierter Ansatz SGML-Dokumente zu speichern wird von der Gesellschaft für Mathematik und Datenverarbeitung (GMD) in Darmstadt im Rahmen des Projekts „VODAK“ verfolgt und ist in [BAN95] genau beschrieben. Das Projekt beschäftigt sich mit der Entwicklung eines objektorientierten Datenbanksystems (ODBMS) namens VODAK, das eigens für die Verwaltung von SGML-Dokumenten konzipiert wurde.
PIC
Abbildung 2.5: Das Klassenkonzept von VODAK

In VODAK wird zu jeder DTD eine eigene Datenstruktur erstellt, die nur Dokumente enthält, die dieser DTD entsprechen. In Abbildung 2.5 wird ein Auszug aus einer solchen VODAK-Datenstruktur gezeigt. Für jeden SGML-Elementyp existiert eine Applikationsklasse in der Dokumententypschicht. Jede dieser Klassen ist von der Klasse DOCUMENT_ELEMENT, der dokumentunabhängigen Schicht abgeleitet. Zu jedem Element eines SGML-Dokuments existiert eine Instanz der dazugehörigen Applikationsklasse und eine Instanz vom Typ DOCUMENT_ELEMENT. In der dokumentunabhängigen Schicht finden sich Informationen über den Aufbau der Datenstruktur und Methoden um sich durch die Klassenhierarchie zu bewegen.

VODAK bildet also die Informationen aus der DTD auf eine Klassenhierarchie ab, das eigentliche SGML-Dokument wird dann durch Instanzen dieser Klassen beschrieben. Auf diese Weise ist es möglich, auf jedem einzelnen Elementtyp eines SGML-Dokuments Operationen zu definieren, die in Methoden der korrespondierenden Klasse realisiert werden. Ein SGML-Dokument kann man sich derart realisiert, als einen Baum vorstellen. Die Teilbäume des Baums sind Instanzen der verschiedenen Klassen der dokumenttypabhängigen Schicht. Die Methoden, um in diesem Baum suchen zu können, werden in der dokumentunabhängigen Schicht definiert und erlauben beispielsweise folgende Abfragen:

  1. Finde alle Abschnitte deren Autor „Christian Mönch“ ist.
  2. Finde das jeweils erste SGML-Element aller gespeicherten Dokumente.
  3. Finde alle Tags (Applikationsklassen), die innerhalb des Tags „Kapitel“ auftreten können.

VODAK bietet uneingeschränkten Zugriff auf die gespeicherten SGML-Dokumente und die dazugehörigen DTD’s. Als Abfragesprache wurde die Vodak Query Language (VQL), für die Definition der Klassenhierarchie die Vodak Modelling Language (VML) entwickelt. Weiterführende Informationen findet man unter [KNS90] oder [BAH94].

2.2.3 Traditionelle Methoden für relationale Datenbanken

Die Struktur von SGML-Dokumenten bietet sich an, die SGML-Dokumente als Baumstruktur zu speichern. Als Beispiel soll wieder das in Abbildung 2.2 dargestellte Dokument dienen. Die in Abbildung 2.3 benutzte Darstellungsweise eignet sich nicht sonderlich gut zur Speicherung in einer Datenbank. Man erkennt, daß jeder Knoten beliebig viele Kinder haben kann. Da man in Datenbankmanagementsystemen (DBMS) normalerweise keine dynamischen Variablen erzeugen kann, ist diese Darstellung nicht geeignet, um sie in eine Datenstruktur umzusetzen. Jeder Baum läßt sich so modifizieren, daß jeder Knoten maximal einen Vater, einen Sohn und einen Bruder hat. Die Idee dabei ist, daß der zweite Sohn eines Knotens immer der rechte Bruder des ersten Sohns des Knotens ist. Durchsucht man den Baum von einem Knoten aus, so findet man den ersten Sohn direkt von diesem Knoten aus, alle weiteren als Brüder des ersten.

Für das genannte Beispiel stellt sich das wie in Abbildung 2.6 gezeigt dar.


PIC
Abbildung 2.6: Vereinfachter Strukturbaum des Beispiels

Mit dieser Struktur kann man einen Baum viel leichter in einer Datenbank abspeichern. Jetzt hat jeder Knoten maximal zwei Verweise, die es sich zu merken gilt.

Eine Möglichkeit ist, den Strukturbaum in einer Klasse zu speichern und die Inhalte der Elemente (Daten) in einer anderen Klasse. Dabei können die Daten entweder direkt in die Datenbank eingebunden werden oder nur als Referenz auf Bitströme vermerkt sein. Zu jedem Knoten des Baums werden eine laufende Nummer, die Nummer des Vaters, des Sohnes und des Bruders gespeichert. Auf diese Art kann man den Baum bequem mittels Depth-First-Search ([Knu73]) traversieren und dabei die gewünschte Operation ausführen.

Eine weitere Möglichkeit ist, jede DTD einer Bewertung zu unterziehen und bestimmte Teile des Markups als Index-Tags auszuzeichnen. Die Index-Tags und deren beinhaltete Daten werden in einer Klasse vorgehalten, die restlichen Informationen in einer anderen. Dadurch verkleinert man die zu durchsuchende Datenmenge. Die Bewertung der DTD’s muß allerdings manuell durchgeführt werden, was einen nicht unerheblichen Mehraufwand bedeutet.