- Fachgebiet Datenbanken und Informationssysteme

Werbung
Speicherung und Verarbeitung von
XML-Dokumenten in relationalen DBMS
Studienarbeit
16. November 2000
Martin Oesterle
Studiengang: Mathematik mit Studienrichtung Informatik
Betreuer: Prof. Dr. Lipeck
UNIVERSITÄT HANNOVER
Institut für Datenbanken
und Informationssysteme
1
Zusammenfassung
Im Zusammenhang mit dem World Wide Web hat XML 1 in den letzten Jahren immer mehr
an Bedeutung gewonnen. Einige Webseiten im Internet werden heutzutage schon dynamisch aus
XML-Dokumenten aufgebaut. Ebenso werden auch große Mengen an Daten im XML-Format verwaltet. Daher ist es nicht verwunderlich, daß es Bestrebungen gibt, eine Anfragesprache für XML zu
definieren, wie es sie in Form von SQL und OQL schon für relationale und objektorientierte Daten
gibt.
Da relationale Datenbanksysteme sehr ausgereift sind und sich in der Praxis bewährt haben,
stellt sich nun die Frage, inwieweit es möglich ist, eine Anfragesprache für XML auf ein solches
System aufzusetzen.
In dieser Arbeit wird ein Verfahren zur Abbildung von Dokumenten im XML-Format auf ein
relationales Datenbanksystem beschrieben. Im gleichen Zuge wird eine Implementierung einer vereinfachten Version der Anfragesprache XML-QL vorgestellt.
1 Extensible
Markup Language
2
Inhaltsverzeichnis
1 Einleitung
5
2 Begriffsdefinition
2.1 Extensible Markup Language (XML) .
2.2 XML-QL . . . . . . . . . . . . . . . .
2.2.1 Einführung und Beispiele . . .
2.2.2 XML-QL Syntax und Semantik
2.2.3 XML-QL Datenmodell . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5
5
6
6
8
10
3 Abbildung eines XML-Dokumentes auf Relationen
3.1 ER-Modell des XML-QL Datenmodells . . . . . . . .
3.2 Transformation des ER-Modells auf Relationen . . .
3.2.1 Relation Kante” . . . . . . . . . . . . . . . .
3.2.2 Relation Blatt’ . . . . . . . . . . . . . . . . .
3.2.3 Relation Attribut . . . . . . . . . . . . . . . .
3.2.4 Relation Dokument . . . . . . . . . . . . . . .
3.3 Importalgorithmus für XML-Dokumente . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
11
11
11
12
12
13
13
13
4 Transformation von XML-QL auf SQL
4.1 Objektstruktur für XML-QL Anfragen .
4.2 Verarbeitung des Where-Abschnittes . .
4.3 Verarbeitung des Construct-Abschnittes
4.4 Beispiel . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
14
14
16
18
20
5 Modulbeschreibung
5.1 Benutzeroberfläche . . .
5.2 Datenbankdesign . . . .
5.2.1 Datenbankmodell
5.2.2 Tabelle tblEdge .
5.2.3 Tabelle tblLeafs .
5.2.4 Tabelle tblAttrs
5.2.5 Tabelle tblDocs .
5.3 Anfrageprozessor . . . .
5.4 Anfrageübersetzer . . .
5.5 Dokumenterzeuger . . .
5.6 Dokument Import . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
23
24
24
24
24
26
26
26
26
26
26
27
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
6 Installation
7 Benutzerhandbuch
7.1 Start des Programmes . . . . . . . .
7.2 Importieren eines XML-Dokumentes
7.3 Laden einer Anfrage . . . . . . . . .
7.4 Speichern einer Anfrage . . . . . . .
7.5 Ausführen einer Anfrage . . . . . . .
7.6 Auswahl der Ausgabeart . . . . . . .
27
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
8 Erfahrungen und Ausblicke
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
28
28
28
28
28
28
28
28
3
9 Anhang A ,SQL-Scripts
9.1 Tabellen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.2 Sequenzen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.3 Funktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
29
29
30
31
1
Einleitung
Diese Arbeit beschreibt die Abbildung mehrerer XML-Dokumente auf eine relationale Datenbank, insbesondere auf das DBMS Oracle 8i. Die Aufgabe besteht darin, ein Programm zu entwickeln, welches eine
Anfrage in XML-QL entgegen nimmt und daraus ein XML-Dokument mit dem Anfrageergebnis erstellt.
Dabei soll die Anfrage von XML-QL in SQL transformiert werden. Die Ergebnistupel der SQL-Anfrage
werden dann wieder in ein XML-Dokument übersetzt.
2
Begriffsdefinition
Im folgenden werden grundlegende Begriffe und Technologien, die in dieser Arbeit benutzt werden, kurz
beschrieben.
2.1
Extensible Markup Language (XML)
XML ist eine vom W3C-Konsortium definierte vereinfachte Untermenge von SGML. Das Ziel von XML
ist es, eine selbstbeschreibende Sprache zum Austausch von Daten und Informationen zu erhalten. Dafür
gibt es in XML die Möglichkeit, eigene Elemente und Strukturen zu beschreiben. Jedes XML-Dokument
besteht aus einer Menge von Elementen, die in Start- und Endetags eingerahmt sind. Jedes Element hat
einen Typ, der durch seinen Namen definiert wird und kann ebenfalls Attribute enthalten, die Namen
und Werte enthalten. Weiterhin kann jedes Element auch noch eine beliebige Anzahl von Unterelementen
enthalten. XML-Dokumente können also beliebig tief geschachtelt und strukturiert werden. Im weiteren
Verlauf werden sich fast alle Beispielanfragen auf Dokumente mit folgender DTD 2 beziehen. Eine DTD
beschreibt die Grammatik für ein XML-Dokument.
<!ELEMENT tree (person*)>
<!ELEMENT person (name,address,hobby*,child*)>
<!ATTLIST person id ID #REQUIRED
age CDATA #REQUIRED
child IDREF #REQUIRED>
<!ELEMENT child (person)>
<!ELEMENT address (#PCDATA)>
<!ELEMENT hobby (#PCDATA)>
Diese DTD stellt einen Familienstammbaum dar, bei dem einer Person ein eindeutiger Schlüssel id und
ein Alter age als Attribute zugewiesen werden muß. Der Name und die Adresse sind als Unterelemente
definiert, die jeweils genau einmal vorkommen müssen. Die Unterelemente Kind und Hobby können
gar nicht oder beliebig oft im Dokument als Unterelement von Person vorhanden sein. Ferner gibt es
noch die Möglichkeit, das Kind einer Person nicht durch ein Unterelement zu beschreiben, sondern als
Referenz innerhalb der Attributliste der Person. Im weiteren Verlauf wird folgendes XML-Dokument
als Datenbasis für XML-QL Anfragen benutzt.
<tree>
<person id=1 age=55>
<name>Peter</name>
<address>4711 Fruitdale Ave.</address>
<child>
<person id=3 age=22>
<name>John</name>
2 Document
Type Definition
5
<address>5361 Columbia Ave.</address>
<hobby>swimming</hobby>
<hobby>cycling</hobby>
</person>
</child>
<child>
<person id=4 age=7>
<name>David</name>
<address>4711 Fruitdale Ave.</address>
</person>
</child>
</person>
<person id=2 age=38 child=4>
<name>Mary</name>
<address>4711 Fruitdale Ave.</address>
<hobby>painting</hobby>
</person>
</tree>
2.2
2.2.1
XML-QL
Einführung und Beispiele
XML-QL 3 [1] ist eine Anfragesprache für XML-Dokumente . Sie erlaubt das Selektieren einzelner
Element der XML-Datei und deren Rekonstruktion zu einem Ergebnisdokument.
Eine XML-QL Anfrage besteht im wesentlichen aus einem Where-Teil und einem Construct-Teil.
Selektieren von Dokumententeilen in der Where-Klausel Der Where-Teil der Anfrage beschreibt
ein Muster, das die zu selektierenden Elemente beschreibt. Angenommen man möchte die Adressen
aller Personen, die David heißen, anfragen. Eine Anfrage in XML-QL hat dann folgende Form:
CONTRUCT <result> {
WHERE
<person>
<name>David</name>
<address>$a</address>
</address>
CONSTRUCT
$a
} </result>
Dieses Anfrage selektiert alle Personen, die mindesten ein Unterelement vom Typ name und ein
Unterelement vom Typ address besitzen und deren Name David ist.
Für jede selektierte Person wird die Variable $a an die jeweilige Adresse gebunden. Eine Variable
wird von Textelementen dadurch unterschieden, daß sie als Präfix ein $ enthält.
Konstruktion des Ergebnisdokumentes in der Construct-Klausel Im obigen Beispiel wurden
alle gefunden Adressen in ein Element mit dem Typ result geschrieben. Will man nun für jeden
Wert der gebundenen Variable ein eigenes Element vom Typ address inklusive dem Namen David
erzeugen, so sieht dies in XML-QL wie folgt aus.
3 Es gibt zur Zeit noch keine offizielle Spezifikation für XML-QL, daher beziehen sich alle Verweise auf eine Spezifikation
immer auf [1]
6
CONTRUCT <result> {
WHERE
<person>
<name>David</name>
<address>$a</address>
</address>
CONSTRUCT
<person>
<name>David</name>
<address>$a</address>
</person>
} </result>
Als Ergebnisdokument erhält man nun das Wurzelelement result mit dem Unterelement person
und den Unterelementen address und name, die die gebundenen Werte der Variable $a und $n
enthalten, wobei die Anzahl der Elemente name und address der Anzahl der Bindungen entsprechen.
Bedingungen für gebundene Variablen Möchte man zum Beispiel die Namen aller Personen, die
älter als 24 Jahre sind, wissen, so kommt man mit den bisherigen Mittel nicht zum Ziel. Es
gibt daher die Möglichkeit in XML-QL, Bedingungen für Variablen in Form eines oder mehrerer
Prädikate anzugeben. Eine Verknüpfung der Attribute mit AND oder OR ist in der vorgestellten
Implementierung möglich, ist allerdings nicht Bestandteil der in [1] beschriebenen Spezifikation,
wobei in [2] eine Verknüpfung der Prädikate auch vorgesehen ist. Eine Anfrage aller Namen von
Personen, die älter als 24 ,aber jünger als 50 sind, sieht dann so aus.
CONTRUCT <result> {
WHERE
<person age=$a>
<name>$n</name>
</address>,
($a>24) AND ($a<50)
CONSTRUCT
<name>$n</name>
} </result>
Kombination von Elementen über Joins Mit Hilfe eines Joins können Anfragen über verschiedene
Dokumente realisiert werden. Hat man nun z.B. ein zweites Dokument in dem es kein Element
person, sondern stattdessen die Elemente man und woman gibt, und man gerne wissen möchte,
welche Person ein Mann ist, so sieht eine Anfrage in XML-QL folgendermaßen aus.
CONSTRUCT <result> {
WHERE
<person>
<name>$n</name>
</person> IN ’Persons.xml’,
<man>
<name>$n</name>
</man> IN ’womanorman.xml’
CONSTRUCT
<person>
7
<name>$n</name>
</person>
} </result>
Als Ergebnis erhält man alle Namen der Person die sowohl in Persons.xml als auch in womanorman.xml als Element vom Typ man auftreten.
Es können allerdings nur Textelemente über einen Join verbunden werden und keine Teilbaumreferenzen.
Optionale Elemente Optionale Elemente werden dann gebraucht, wenn man Elemente sucht, die ein
Unterelement haben können, aber nicht haben müssen. Sucht man zum Beispiel alle Namen von
Personen, die entweder kein Hobby oder als Hobby schwimmen haben, kommt man auf folgende
Anfrage. Der optionale Teil wird in eckige Klammern gesetzt.
CONSTRUCT <result> {
WHERE
<person>
<name>$n</name>
[<hobby>swimming</hobby>]
</person>,
CONSTRUCT
<person>
<name>$n</name>
</person>
} </result>
In dieser Arbeit darf innerhalb eines optionalen Elementes kein Unterelement als optional definiert
werden, ebenfalls darf das Wurzelelement eines Anfragemusters nicht optional sein.
2.2.2
XML-QL Syntax und Semantik
In diesem Abschnitt wird zuerst die Syntax der implementierten XML-QL Anfragesprache beschrieben.
Danach wird die Semantik von XML-QL beschrieben.
XML-QL Syntax In dieser Arbeit wird folgende XML-QL Syntax verwendet, die eine Untermenge
der in der XML-QL Spezifikation definierten Syntax ist. 4 Der Syntax ist in EBNF5 beschrieben.
<Query>
::= ’CONSTRUCT’
<Starttag><QueryBlock><Endtag>
<QueryBlock> ::= <Starttag>
’{’<WherePart><ConstPart>’}’
<Endtag>
<Starttag>
::= ’<’<Word>{’ ’<Attribute>}’>’
<Endtag>
::= ’</’<Word>’>’
4 Bei der Produktion Predicate handelt es sich nicht um eine Untermenge der Spezifikation, sondern um eine Erweiterung, da eine Schachtelung der Prädikate zugelassen wird.
5 Erweiterte Backus-Naur Form
8
<Attribute>
::= <Word>’=’(<Quotedchars>|<Variable>)
<Quotedchars>::= ’’’<Characters>’’’
<Characters> ::= {<Word>|<Whitespace>}
<Word>
::= ’a’-’z’ | ’A’-’Z’ | ’0’-’9’ |
’.’ | ’,’ | ’_’ | ’/’ | ’:’
<WherePart>
::= ’WHERE’ <WherePat>
{’,’ (<WherePat>|<Predicate>)}
<ConstPart>
::= ’CONSTRUCT’ <Pattern>{<Pattern>}
<Pattern>
::= <Starttag>
(<Characters>|<Variable>|<Pattern>)
<Endtag>
<WherePat>
::= <Starttag>
(<Characters>|<Variable>|
<WherePat>| (’[’<Pattern>’]))
<Endtag>
<Variable>
::= ’$’<Word>
<Predicate>
::= <Expression> |
’(’ <Predicate> ’)’
’AND’ ’(’ <Predicate> ’)’ |
’(’ <Predicate> ’)’
’OR’ ’(’ <Predicate> ’)’
<Expression> ::= <Variable> <RelOp>
(<Quotedchars>|<Variable>)
<RelOp>
::= ’=’ | ’!=’ | ’>=’ | ’<=’ | ’>’ | ’<’
XML-QL Semantik Angenommen man hat eine XML-QL Anfrage der Form WHERE P CONSTRUCT C, wobei P für ein beliebiges Pattern mit seinen Prädikaten steht, und C für ein
beliebiges Constructpattern. P besteht also aus mehreren Bedingungen, die Tupel von Variablen
x1 , . . . , xk binden. Die Semantik besteht nun aus zwei Teilen.
Zum einen der WHERE-Teil der Anfrage. Hier wird eine Relation R(x1 , . . . , xk ) mit jeweils einer
Spalte pro gebundener Variablen erzeugt. Jedes Tupel der Relation besteht nun aus denjenigen
Werten der gebundenen Variablen, die den Bedingungen in P genügen. Jede dieser Variablen wird
an eine Teilbaumreferenz oder an einen atomaren Wert gebunden.
Nimmt man nun an, man hat n Ergebnistupel erhalten, so geht man nun zum zweiten Teil über,
nämlich dem Constructpattern C. C beschreibt eine Schablone C(x1 , . . . , xk ), die an einige der
Variablen gebunden ist. Man bezeichnet die einzelnen Tupel von R nun als xi1 , . . . , xik mit i =
[1, n]. Nun wird für jedes Tupel aus R ein XML-Fragment Ci := C(xi1 , . . . , xik ) erzeugt. Das
Anfrageergebnis ist dann die Vereinigung aus allen Ci .
9
[1]
tree
[2]
person
person
[3]
[age=55]
[4]
[age=38]
name
name
Peter
Mary
address
Fruitdale Av .
Abbildung 1: XML-QL Datenmodell
2.2.3
XML-QL Datenmodell
Wie jede Anfragesprache besitzt auch XML-QL ein Datenmodell, auf dem es aufbaut. Dieses Datenmodell besteht im wesentlichen aus einem Graphen. Dieser Graph setzt sich aus einer Menge von Knoten
zusammen, wobei jedem Knoten genau eine eindeutige OID 6 zugewiesen wird. Die Kanten des Graphen
werden mit dem Namen des XML-Tags beschriftet. Die Attribute des Tags werden als Namen/WertePaare an den Knoten gebunden. Sämtliche Blätter des Graphen enthalten Textkonstanten. Weiterhin
gilt, daß es nur ein Wurzelelement geben darf. Betrachtet man nun folgendes Beispiel:
<tree>
<person age=’55’>
<name>Peter</name>
</person>
<person age=’38’>
<name>Mary</name>
<address>Fruitdale Ave.</address>
</person>
</tree>
Die zum Beispiel gehörende Instanz eines XML-QL Datenmodells besteht aus einen Wurzelknoten, von
dem ein Kante für das Element tree ausgeht. Von diesem Element gehen wiederum zwei Kanten mit
der Beschriftung Person aus. Die einzelnen Knoten haben jeweils das Attribut age mit den zugehörigen
Werten. Von den beiden Knoten gehen dann ebenfalls Kanten aus ,die mit Name beschriftet sind. Da
6 Object
Identifier
10
es keine Hierarchistufe unterhalb von Name gibt, handelt es sich bei den Knoten um Blätter und ihnen
sind die Namen der Personen zugeordnet (Abbildung auf Seite 10).
3
Abbildung eines XML-Dokumentes auf Relationen
In diesem Abschnitt wird zuerst die Abbildung des XML-QL Datenmodells auf ein ER-Schema und dann
die Transformation des ER-Schemas auf Relationen beschrieben. Danach wird auf den Algorithmus zum
Import eines XML-Dokumentes eingegangen.
3.1
ER-Modell des XML-QL Datenmodells
Das XML-QL Datenmodell beschreibt einen Graphen. Es liegt nun nahe diesen Graphen in einem ERModell zu beschreiben, siehe Abbildung auf Seite 12. Da es möglich sein soll, mehrere Dokumente in
einer Datenbank zu halten, gibt es noch eine Beziehung zwischen jedem Knoten und dem Dokument,
zu dem er gehört.
Das ER-Schema besteht im wesentlich aus den drei Entitäten Knoten, Blatt und Dokument. Im
folgenden werden die einzelnen Entitaten und Beziehungen beschrieben.
Entität Dokument: Die Entität Dokument enthält die eingearbeiteten Dokumente. Als Attribute
besitzt sie eine eindeutige DokumentId , welches auch zugleich der Primärschlüssel ist, und ferner
den Namen des Dokumentes, der ebenfalls eindeutig sein muß.
Entität Blatt: Die Entität Blatt beschreibt die Blätter des Datenmodells. Zur Vereinfachung des ERSchemas werden Attribute ebenfalls als Blätter betrachtet. Um die Information, ob es sich um ein
Blatt oder ein Attribut handelt, nicht zu verlieren, wird ein Attribut Typ eingeführt. Ein weiteres
Attribut Wert enthält den Text, der an das Blatt bzw. Attribut gebunden ist. Handelt es sich bei
dem Attribut um eine Referenz, so wird die Referenz im Attribut Wert eingetragen. Zu guter letzt
besitzt jedes Blatt/Attribut noch eine eindeutige BlattId, welches zugleich der Primärschlüssel ist.
Entität Knoten: Jeder Knoten des Datenmodells besitzt eine eindeutige KnotenId als Attribut und
zugleich als Primärschlüssel. Weiterhin wird noch ein Attribut Tiefe eingeführt, welches die Tiefe
des Teilbaumes unterhalb des Knotens enthält.
Beziehung gehört zu: Jedem Knoten ist genau ein Dokument zugeordnet.
Beziehung ist ein: Einige Knoten des Datenmodells sind Blätter oder Attribute im vereinfachten
Modell.
Beziehung Kante: Die Beziehung Kante modelliert die Graphstruktur des Datenmodells, und besitzt
daher einen Quell- und einen Zielknoten. Eine weitere Vereinfachung des Datenmodells besteht
darin, Referenzen von einem Knoten auf einen anderen nicht als Kante zu modellieren sondern als
Typ eines Attributs. Deshalb kann man von einem Baum sprechen und fordern, daß jeder Knoten,
der ein Quellknoten ist, maximal einmal als Zielknoten auftreten darf.
3.2
Transformation des ER-Modells auf Relationen
Die Entitäten und Beziehungen werden nun auf einzelne Relationen verteilt. Im ersten Schritt wird für
jede Entität und jede Beziehung eine eigene Relation erzeugt. Nun werden die 1:1 und 1:N Beziehungen
auf die Entitätsrelationen aufgeteilt. Man erhält als Zwischenschritt dann folgende Relationen:
Knoten(Id, BlattId, DokumentId, T ief e)
Kante(KnotenId, KnotenId, N ame
| {z } | {z }
von
nach
Blatt(Id, W ert, T yp)
Dokument(Id, N ame)
11
Abbildung 2: ER-Modell
Da es sich bei der Entität Blatt um einen Knoten handelt, von dem keine Kante mehr ausgeht, kann
man die Relation Knoten in die Relation Kante einsetzen. Da jeder innere Knoten außer der Wurzel
immer im von-Teil der Kantenrelation auftritt, reicht es aus die BalttId und die DokumentId nur einmal
zu speichern. Man erhält dann folgende Relation Kante’.
Kante0 (QuellId, ZielId, BlattId, DokumentId, T ief e, N ame)
{z
}
| {z } |
nach
von
Nun wird noch die Relation Blatt anhand des Attributes Typ horizontal partitioniert. Dadurch erhält
man die zwei neuen Relationen.
Blatt0 (Id, W ert)
Attribut(Id, W ert)
Um die Information über den Typ des Blattes nicht zu verlieren, wird das Attribut Typ in die Relation
Kante’ übernommen. Weiterhin wird BlattId in die Attribute BlattId’ und AttributId aufgeteilt. Als
endgültiges Relationenmodell erhält man dann folgende Relationen.
Kante00 (QuellId, ZielId, BlattId0 , AttributId, DokumentId, T yp, N ame, T ief e) Blatt0 (Id, W ert)
Attribut(Id, W ert)
Dokument(Id, N ame)
3.2.1
Relation Kante”
Attribut
QuellId
ZielId
BlattId’
AttributId
DokumentId
3.2.2
Null
nein
nein
ja
ja
nein
eindeutig
nein
nein
ja
ja
ja
PK
ja
ja
nein
nein
nein
FK
nein
nein
auf Blatt.Id
auf Attribut.Id
auf Dokument.Id
Relation Blatt’
Attribut
Id
Wert
Null
nein
nein
eindeutig
ja
nein
PK
ja
nein
FK
nein
nein
12
3.2.3
Relation Attribut
Attribut
Id
Wert
3.2.4
eindeutig
ja
nein
PK
ja
nein
FK
nein
nein
PK
ja
nein
FK
nein
nein
Relation Dokument
Attribut
Id
Wert
3.3
Null
nein
nein
Null
nein
nein
eindeutig
ja
ja
Importalgorithmus für XML-Dokumente
Für die Einarbeitung eines XML-Dokumentes muß die Eingabedatei geparst werden. Bei dem vorgestellten Algorithmus wird davon ausgegangen, daß es sich um einen eventgesteuerten Parser wie zum
Beispiel die SAX-Parser7 handelt.
Um die Arbeitsweise des Algorithmus übersichtlicher erklären zu können, wird auf ein vereinfachtes
Datenmodell zurückgegriffen. Es besteht im wesentlich aus einer Relation.
Kante(QuellId, ZielId, T yp, N ame, Zielwert, T ief e)
Das Attribut Zielwert enthält den Wert des Zielknotens, falls es sich dabei um ein Blatt oder ein
Attribut handelt.
Definition: Sei S ein Stack. Die Funktion depth(Objekt) gibt die Anzahl der über dem Objekt liegenden Elemente von S zurück. S habe folgende Eigenschaften:
1. S enthält nur Objekt vom Typ Kante
2. Nach jedem push() gilt:
∀ki ∈ S : ki .tief e = max{ki .tief e, depth(ki .tief e}
Im folgendes werden die Arbeitsschritte innerhalb der Ereignisse beschrieben.
Dokumentanfang: Dieses Ereignis wird am Anfang eines Dokumentes ausgelöst.
Eingabe:keine
Aktion:keine
Ausgabe:keine
Starttag: Dieses Ereignis wird ausgelöst, wenn der Parser auf ein Starttag trifft.
Eingabe:Name tag des Tags, Eine Liste der Attribute AttrList
Aktion:
Kante k = S.top()
Erzeuge neue Kante k 0
k 0 .QuellId = k.ZielId
k 0 .ZielId = neue KantenId
k 0 .N ame = tag
k 0 .T yp = ref erenz
S.push(k 0 )
Für jedes attr in AttrList
7 SAX
(Simple Api for XML)
13
Erzeuge neue Kante k 00
k 00 .QuellId = k.ZielId
k 00 .ZielId = leer
k 00 .N ame = attr.name
k 00 .Zielwert = attr.wert
Falls wert eine Referenz ist, dann
k 00 .T yp = attrref , sonst k 00 .T yp = attribut
gebe attr aus
Ausgabe: Für jedes Attribut eine Kante k 00
Endetag: Dieses Ereignis wird ausgelöst, wenn der Parser auf ein Endetag trifft.
Eingabe:keine
Aktion:
Kante k = S.pop()
Ausgabe:Kante k
Zeichenkette Diese Ereignis wird ausgelöst, wenn der Parser auf Text innerhalb eines Elementes trifft.
Eingabe:Gefundener Text txt
Aktion:
Kante k = S.pop()
k.T yp = Blatt
k.W ert = txt
S.push(k)
Ausgabe:keine
Dokumentende: Dieses Ereignis wird am Ende eines XML-Dokumentes vom Parser ausgelöst.
Eingabe:keine
Aktion:
Der Algorithmus wird beendet
Ausgabe:keine
4
Transformation von XML-QL auf SQL
Im folgenden Abschnitt werden die Algorithmen vorgestellt, die zum einen eine XML-QL Anfrage in
SQL übersetzen und zum anderen das Ergebnis der Anfrage wieder in ein XML-Dokument wandeln.
Der Datenfluß der Anfrageverarbeitung ist auf Seite 15 beschrieben.
Die XML-QL Anfrage wird vom Parser ausgewertet. Der Parser erzeugt dabei eine Objektstruktur
der Anfrage. Aus dem Where-Teil der Objektstruktur wird die SQL-Anfrage generiert. Nachdem die
SQL-Anfrage ausgeführt wurde, wird mit Hilfe der Ergebnistupel und des Construct-Teils der Objektstruktur das Ergebnisdokument im XML-Format erzeugt.
4.1
Objektstruktur für XML-QL Anfragen
Um die XML-QL Anfrage verarbeiten zu können, muß diese in eine für den Algorithmus verwendbare
Struktur gebracht werden. In dieser Arbeit wird dafür das Interpreterentwurfsmuster in Zusammenhang mit dem Besucherentwurfsmuster verwendet. Eine sehr gute Abhandlung ist in [7] zu finden. Eine
14
XML-QL
Anfrage
Parser
Objektstruktur
Generierung des
SQL-Statement
SQLStatement
DBMS
Ausführung
des
SQL-Statements
Konstruktion
des Ergebnisdokumentes
Tupelmenge
XMLDokument
Abbildung 3: Datenfluss
allgemeine Erläuterung dieser Entwurfsmuster würde den Rahmen dieser Arbeit sprengen. Das Interpreterentwurfsmuster ist eine objektorientierte Implementierung des AST8 einer XML-QL Anfrage, wie
in [5] und [6] vorgeschlagen. Im folgenden werden alle Klassen des Objektmodells beschrieben.
Klasse ASTQuery Die Klasse ASTQuery kapselt die gesamte XML-QL Anfrage und hat als Attribut
lediglich den Namen des Tags des äußeren Construct-Blockes.
Klasse
name
queryBlock
ASTQuery
Name des Wurzelelementes der Anfrage
Referenz auf eine Objekt der Klasse ASTQueryBlock
Klasse ASTQueryBlock Die Klasse ASTQueryBlock kapselt einen Anfrageblock in XML-QL und
enthält daher Verweise auf die Wherepatterns, das Constructpattern und die Prädikate.
Klasse
wherePatterns
predicate
contstructPat
ASTQueryBlock
Eine Menge von Verweisen auf ASTElement-Objekte
Ein Verweis auf das Wurzelobjekt der ASTPredicateStruktur
Verweis auf ein ASTElement-Objekt
Klasse ASTElement Die Klasse ASTElement kapselt eine XML-Element, mit dem Unterschied, daß
es als Unterelement auch Variablen enthalten kann.
Klasse
ASTElement
isRoot
Wurzelement (ja oder nein)
isOptional
Flag, ob Element optional ist
name
Name des Elements
subElement Verweis auf Objekt der Klasse ASTElement,ASTString oder ASTVariable
8 Abstrakter
Syntax Baum
15
Klasse ASTString Die Klasse ASTString kapselt eine Zeichenfolge.
Klasse
text
ASTString
Zeichenkette
Klasse ASTVariable Die Klasse ASTVariable kapselt eine Variable.
Klasse
varName
ASTVariable
Variablenbezeichner
Klasse ASTPredicate Die Klasse ASTPredicate kapselt die geschachtelten Bedingungen.
Klasse
operator
left
right
ASTPredicate
Verknüpfungsoperator and oder or
Verweis auf ASTPredicate, ASTString oder ASTVariable
Verweis auf ASTPredicate, ASTString oder ASTVariable
Klasse Context Die Klasse Context enthält alle global verfügbaren Informationen für den Algorithmus.
Klasse
Context
select
Container für die Elemente des Selectteils
where
Container für die Elemente des Whereteils
from
Container für die Elemente des Fromteils
stack
Stack für die Tabellenaliase
hashtable
Dictionary für die Zurordnung der Variablen zu den
Tabellenaliasen.
newAlias() Funktion zum Erzeugen neuer Tabellenaliase
4.2
Verarbeitung des Where-Abschnittes
Dieser Abschnitt beschäftigt sich mit dem Algorithmus zur Erzeugung des SQL-Statements. Der gesamte Algorithmus zur Verarbeitung des Where-Abschnittes besteht aus zwei Teilen. Der erste Teil ist
Algorithmus A und arbeitet die Wherepatterns ab und startet in der Objektstruktur bei jedem Element
aus ASTQueryBlock.wherePatterns .
Der zweite Teil ist recht einfach. Als Einstiegspunkt in die Objektstruktur wird das Wurzelobjekt
der Klasse ASTPredicate benutzt. Es wird ein Inorderdurchlauf gestartet, bei dem die Bedingungen
an den Whereteil der SQL-Anfrage angehängt werden. Die Auflösung der Variablen erfolgt über die
Hashtabelle des Contextobjekts.
Bemerkung: Bei der Implementierung des optionalen Elementes wird im Gegensatz zu [3] keine UNION verwendet, da bei einer Vielzahl von optionalen Elementen jede Kombination der Elemente
einzeln angefragt wird. In dieser Arbeit wird das optionale Element über einen temporären View
der Kantenrelation und einem anschließenden outer join realisiert.
Definition: Im folgenden bezeichnet e immer die aktuelle Instanz von ASTElement. Der Pseudocode
lehnt sich an die Programmiersprache Java an.
Methode ASTElement.algorithmusA(Context c)
1.Hole aktuellen Alias vom Stack
oldAlias=c.stack.top()
2.Erzeuge neuen Alias und speichere ihn auf den Stack
aktAlias=c.newAlias()
16
c.stack.push(aktAlias)
3.Erweitere From-Klausel um neuen Alias, falls Element nicht Optional
If not e.isOptional then
c.from.add(aktAlias )
4.Ist e Wurzelelement ? Wenn ja bilde joins
If e.isRoot then
4.1 Unterscheide zwischen optionalen und nicht optionalen Element
if e.isOptional then
OptView=SELECT * FROM Kante WHERE Name=e.name
c.from.add(OptView aktAlias )
c.where.add(oldAlias.ZielId=aktAlias.QuellId(+) )
else
c.where.add(oldAlias.ZielId=aktAlias.QuellId )
5.Erzeuge Bedingung für den Kantennamen
c.where.add(aktAlias=e.name )
6.Für jedes Subelement e’ von e führe folgende Schritte aus
for each e’ in subElements do
6.1.Falls es eine Element ist, tue ...
if e’ instanceof ASTElement then
6.1.1.Führe Algorithmus fuer Subelement aus
e’.algorithmusA(c)
6.2.Falls es ein Wert ist, tue ...
if e’ instanceof ASTString then
6.2.1. Erzeuge Bedingung
c.where.add(aktAlias.wert=e’.text )
6.3.Falls es eine Variable ist, tue ...
if e’ instanceof ASTVariable then
6.3.1.Erweitere Select-Teil um Bindungen
c.select.add(aktAlias.Typ,aktAlias.ZielId
aktAlias.Zielwert,aktAlias.Tiefe )
6.3.2.Ist Variablenname schon in der Hashtabelle,
dann erzeuge join-Bedingung, sonst speichere sie in die Hashtabelle
if e’.varname in c.hashtable then
c.where.add(c.hastable.get(e’.varname)=aktAlias.Wert )
else
c.hashtable.add(e’.varname.aktAlias.Wert)
7.Räume Stack auf
c.stack.pop()
17
Als Beispiel dient folgende ,bereits aus der Einführung bekannte Anfrage mit optionalem Element.
CONSTRUCT <result> {
WHERE
<person>
<name>$n</name>
[<hobby>swimming</hobby>]
</person>,
CONSTRUCT
<person>
<name>$n</name>
</person>
} </result>
Beim Durchlaufen des Where-Abschnittes trifft der Algorithmus zuerst auf das Element Person. Als
Zwischenergebnis erhält man:
SELECT
FROM
KanteA
WHERE
A.N ame =0 person0
Als nächstes tritt das Element Name als Variable auf, daraus folgt dann.
SELECT
B.T yp, B.ZielId, B.ZielW ert, B.T ief e
FROM
KanteA, KanteB
WHERE
A.N ame =0 person0 AND
A.ZielId = B.QuellId AND B.N ame =0 name0
Das darauf folgende Element ist optional, es wird also ein View als Unterabfrage gebildet. Das
endgültige SQL-Statement sieht nun wie folgt aus.
SELECT
B.T yp, B.ZielId, B.ZielW ert, B.T ief e
FROM
KanteA, KanteB,
(SELECT * FROM Kante WHERE Name=’hobby’) C
WHERE
A.N ame =0 person0 AND
A.ZielId = B.QuellId AND B.N ame =0 name0 AND
A.ZielId = C.QuellId AND C.N ame =0 hobby 0 AND
C.ZielW ert =0 swimming 0
4.3
Verarbeitung des Construct-Abschnittes
Wie im Abschnitt über die Semantik von XML-QL schon beschrieben, erhält man für das Contructpattern C eine Menge von Tupeln Ci := C(xi1 , . . . , xik ) mit i = [1, n] bei n Anfrageergebnissen aus dem
18
Where-Abschnitt. Bei der Rekonstruktion dient das Objekt ASTQueryBlock.constructPat als Einstiegspunkt. Der Algorithmus durchläuft das Constructpattern für jedes Tupel Ci des Anfrageergebnisses. Bei
jeder Iteration sind zwei Fälle zu unterscheiden. Zum einem der Fall, daß ein xj , j = [1, k] an keine Teilbaumreferenz gebunden ist, dann wird einfach der an xj gebundene Wert eingesetzt. Zum anderen
der Fall, daës sich um eine Teilbaumreferenz handelt, wobei es dabei verschiedene Möglichkeiten zur
Rekonstruktion gibt.
Das naive Verfahren besteht darin, den Baum rekursiv Stufe für Stufe mit Hilfe von vorbereiteten SQL-Anweisungen zu erstellen. Die Anzahl der benötigten SQL-Anfragen ist dabei proportional
zur Tiefe des Teilbaumes. Eine anderes Vorgehen macht sich zu Nutze, daß beim Einlesen des XMLDokumentes für jeden Knoten die Tiefe des darunterliegenden Teilbaumes gespeichert wurde. Es ist
mit dieser Information möglich, den Teilbaum mit Hilfe nur eines SQL-Statements zu rekonstruieren.
Sei nun d die Tiefe des Teilbaumes und s die Id der Teilbaumwurzel, dann hat das SQL-Statement in
Oracle-SQL folgende Form:
SELECT
k1 .N ame, k1 .Zielwert, . . . , kd .N ame, kd .Zielwert
FROM
Kante k1 , . . . , Kante kd
WHERE
(k1 .QuellId = s) AND
(k1 .ZielId = k2 .QuellId(+)) AND
...
(kd−1 .ZielId = kd .QuellId(+))
Um das Verfahren an einem praktischen Beispiel zu erläutern, soll dieser Teilbaum aus der Datenbank
rekonstruiert werden.
<person id=3 age=22>
<name>John</name>
<address>5361 Columbia Ave.</address>
<child>
<person>
<name>Dave</name>
</person>
</child>
</person>
Das SQL-Statement sieht dann bei einer Teilbaumtiefe von 3 folgendermaßen aus:
SELECT
k1 .N ame, k1 .Zielwert, k2 .N ame, k2 .Zielwert, k3 .N ame, k3 .Zielwert
FROM
Kante k1 , Kante k2 , Kante k3
WHERE
k1 .QuellId = 3 AND
k1 .ZielId = k2 .QuellId(+) AND
k2 .ZielId = k3 .QuellId(+)
Das Ergebnis der Anfrage ist auf Seite 20 in Tabellenform dargestellt. Man kann daraus nun den
Teilbaum wieder rekonstruieren.
19
k1 .N ame
id
age
name
address
child
k1 .Zielwert
3
22
John
5361 Col . . .
(null)
k2 .N ame
(null)
(null)
(null)
(null)
person
k2 .Zielwert
(null)
(null)
(null)
(null)
(null)
k3 .N ame
(null)
(null)
(null)
(null)
name
k3 .Zielwert
(null)
(null)
(null)
(null)
Dave
Tabelle 1: Anfrageergebnis der Teilbaumrekonstruktion
4.4
Beispiel
In diesem Beispiel wird der gesamte Datenfluß durchgespielt. Als XML-Dokument wird das schon bekannte Beispiel aus Kapitel 2.1 benutzt.
<tree>
<person id=1 age=55>
<name>Peter</name>
<address>4711 Fruitdale Ave.</address>
<child>
<person id=3 age=22>
<name>John</name>
<address>5361 Columbia Ave.</address>
<hobby>swimming</hobby>
<hobby>cycling</hobby>
</person>
</child>
<child>
<person id=4 age=7>
<name>David</name>
<address>4711 Fruitdale Ave.</address>
</person>
</child>
</person>
<person id=2 age=38 child=4>
<name>Mary</name>
<address>4711 Fruitdale Ave.</address>
<hobby>painting</hobby>
</person>
</tree>
Möchte man nun zum Beispiel die Namen und die Kinder aller Personen, die in der 4711 Fruitdale
Ave. wohnen, ausgegeben haben, sieht die Beispielanfrage wie folgt aus.
CONSTRUCT <result> {
WHERE
<person>
<name>$n</name>
<address>4711 Fruitdale Ave.</address>
<child>$c</child>
</person>,
CONSTRUCT
<person>
<name>$n</name>
20
QuellId
0
1
2
2
2
2
2
7
8
8
8
8
8
8
2
15
16
16
16
16
1
21
21
21
21
21
21
ZielId
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Typ
referenz
referenz
attribut
attribut
blatt
blatt
referenz
referenz
attribut
attribut
blatt
blatt
blatt
blatt
referenz
referenz
attribut
attribut
blatt
blatt
referenz
attribut
attribut
attrref
blatt
blatt
blatt
Name
tree
person
id
age
name
address
child
person
id
age
name
address
hobby
hobby
child
person
id
age
name
address
person
id
age
child
name
address
hobby
Zielwert
1
55
Peter
4711 Fruitdale Ave.
3
22
John
5461 Columbia Ave.
swimming
cycling
4
7
David
4711 Fruitdale Ave.
2
38
4
Mary
4711 Fruitdale Ave.
painting
Tiefe
4
3
0
0
0
0
2
1
0
0
0
0
0
0
2
1
0
0
0
0
1
0
0
0
0
0
0
Tabelle 2: Beispielkantentabelle
<hobby>babysitting</hobby>
<child>$c</child>
</person>
} </result>
Im ersten Schritt wird das XML-Dokument in die Datenbank importiert. Dazu wird das XMLDokument durch den Importalgorithmus auf die Tabelle auf Seite 21 abgebildet. Im nächsten Schritt
wird durch einen Parser die Objektstruktur aus Seite 22 erzeugt. Danach wird die SQL-Anfrage anhand
des beschriebenen Algorithmus generiert. Als Ergebnis erhält man dann folgendes SQL-Statement.
SELECT
B.T yp AS n Typ,
B.ZielId AS n ZId,
B.Zielwert AS n ZWert,
B.T ief e AS n Tiefe,
D.T yp AS c Typ,
D.ZielId AS c ZId,
D.Zielwert AS c ZWert,
D.T ief e AS c Tiefe
FROM
KanteA,
KanteB,
21
Abbildung 4: Objektstruktur der Beispielanfrage
KanteC,
KanteD
WHERE
A.N ame =0 person0 AND
A.ZielId = B.QuellId AND B.N ame =0 N ame0
A.ZielId = C.QuellId AND C.N ame =0 address0 AND
C.Zielwert =0 4711F ruitdaleAve.0 AND
A.ZielId = D.QuellId AND D.N ame =0 child0
Die Anfrage liefert als Ergebnis alle Bindungen der Variablen $n und $c.
n Typ
blatt
blatt
blatt
n ZId
5
5
25
n ZWert
Peter
Peter
Mary
n Tiefe
0
0
0
c Typ
referenz
referenz
attrref
c ZId
7
15
24
c ZWert
4
c Tiefe
2
2
0
Nachdem nun die Bindungen der Variablen gefunden wurde, wird nun der Construct-Abschnitt betrachtet. Dabei wird für jedes Tupel der Ergebnismenge das Constructpattern durchlaufen. Die Variable
$n ist immer als atomarer Wert an einen Text gebunden und wird einfach eingesetzt. Die Variable $c
ist zweimal an Teilbaumreferenzen gebunden und einmal an eine Attributreferenz. Die Attributreferenz
wird ebenfalls einfach eingesetzt. Für die erste Teilbaumreferenz auf den Zielknoten 7 wird folgenden
SQL-Statement erzeugt.
SELECT
A.N ame,
A.Zielwert,
A.T yp,
B.N ame,
B.Zielwert
B.T yp
22
FROM
KanteA,KanteB
WHERE
A.QuellId = 7 AND
A.ZielId = B.QuellId(+) AND
Als Anfragergebnis erhält man folgende Tabelle.
A.Name
person
person
person
person
person
person
A.Zielwert
A.Typ
referenz
referenz
referenz
referenz
referenz
referenz
B.Name
id
age
name
address
hobby
hobby
B.Zielwert
3
2
John
5361 Columbia Ave.
swimming
cycling
B.Typ
attribut
attribut
blatt
blatt
blatt
blatt
Beim zweiten Teilbaum wird ebenso verfahren. Aus den Anfragergebnissen der Teilbaumanfragen
und den Einsetzungen wird das XML-Dokument erzeugt.
<?xml version=’1.0’?>
<result>
<person>
<name>Peter</name>
<hobby>babysitting</hobby>
<child>
<person id=3 age=22>
<name>John</name>
<address>5361 Columbia Ave.</address>
<hobby>swimming</hobby>
<hobby>cycling</hobby>
</person>
</child>
</person>
<person>
<name>Peter</name>
<hobby>babysitting</hobby>
<child>
<person id=4 age=7>
<name>David</name>
<address>4711 Fruitdale Ave.</address>
</person>
</child>
</person>
<person child=4>
<hobby>babysitting</hobby>
</person>
</result>
5
Modulbeschreibung
Ein Gesamtmodulübersicht ist auf Seite 24 zu sehen. In den folgenden Abschnitten wird auf die einzelnen
Module und ihre Funktionen kurz eingegangen. Die genaue Dokumentation zu den einzelnen Packages
und Klassen ist als javadoc vorhanden.
23
!!
# $
# $%%& &
- - ."."''/./02.1
021
3344 !!"" 5
5
''6!6!77 %
'%
(
))%
%*+%,*+ , '%
(
Abbildung 5: Modulübersicht
5.1
Benutzeroberfläche
Die Benutzeroberfläche besteht aus einem horizontal geteilten Fenster. Im oberen Fenster werden Anfragen entgegengenommen. Im unteren Fenster werden Fehlermeldungen und Anfragergebnisse ausgegeben.
Die Unterscheidung zwischen Fehlermeldungen und Anfrageergebnissen wird über einen Reitersteuerelement realisiert. Im Auswahlmenü stehen Funktionen zum Importieren von XML-Dokumenten, Starten
von Anfragen, Speichern von Anfragen, Laden von Anfragen und zum Beenden des Programmes bereit.
Außerdem kann ausgewählt werden, ob die Ausgabe im Fenster oder in eine Datei erfolgen soll.
5.2
5.2.1
Datenbankdesign
Datenbankmodell
In diesem Abschnitt wird auf die Implementierung des Datenbankentwurfs auf Oracle 8i eingegangen und
beschrieben. Die einzelnen Tabellen werden mit ihren Datentypen, Indexen und Intergritätsbedingungen
beschrieben. Die SQL- Erstellungsskripte sind im Anhang enthalten.
5.2.2
Tabelle tblEdge
Die Tabelle tblEdge ist die Implementierung der Relation Kante00 .
24
Abbildung 6: Benutzeroberfläche
Feldname
SourceId
Feldtyp
integer
Null
nein
TargetId
integer
ja
LeafId
integer
ja
AttrId
integer
ja
DocId
integer
nein
EdgeName
Type
varchar(30)
char(4)
nein
nein
Depth
smallint
nein
Inhalt
Id des Startknoten der Kante, wird automatisch über eine Sequenz generiert
Id des Zielknoten der Kante, Fremdschlüssel auf tblEdge(SourceId)
Id des Elementwertes, falls es sich um
ein Blatt handelt, Fremdschlüssel auf
tblLeafs(LeafId)
Id des Attributwertes, falls es sich um
ein Attribut handelt, Fremdschlüssel
auf tblAttrs(AttrId)
Id des Dokumentes, in aus dem die Kante generiert wurde, Fremdschlüssel auf
tblDocs(DocId)
Name der Kante
Typ
des
Zielknotens
(Referenz,Blatt,Attribut,Attributreferenz)
Tiefe des Teilbaumes unterhalb des
Zielknotens
Primärschlüssel (SourceId,TargetId,LeafId,AttrId,DocId,EdgeName)
Indexe Es wird jeweils ein Index über die Felder SourceId,(EdgeName und TargetId), Leafid, AttrId
und DocId gebildet.
25
5.2.3
Tabelle tblLeafs
Die Tabelle tblLeafs ist die Implementierung der Relation Blatt0
Feldname
LeafId
Feldtyp
integer
Null
nein
Value
varchar(255)
ja
Inhalt
Id des Blattes bzw. Elementwertes, wird
automatisch über eine Sequenz generiert
Wert des Blattes (Zeichenkette)
Primärschlüssel (LeafId)
Indexe Es wird jeweils ein Index über die Felder LeafId und Value gebildet.
5.2.4
Tabelle tblAttrs
Die Tabelle tblAttrs ist die Implementierung der Relation Attribut
Feldname
AttrId
Feldtyp
integer
Null
nein
Value
varchar(128)
ja
Inhalt
Id des Attributes, wird automatisch
über eine Sequenz generiert
Wert des Attributes (Zeichenkette)
Primärschlüssel (AttrId)
Indexe Es wird jeweils ein Index über die Felder AttrId und Value gebildet.
5.2.5
Tabelle tblDocs
Die Tabelle tblDocs ist die Implementierung der Relation Dokument
Feldname
DocId
Feldtyp
integer
Null
nein
Value
varchar(128)
ja
Inhalt
Id des Dokumentes, wird automatisch
über die Sequenz SEQ DOCID generiert
Dokumentenname
Primärschlüssel (DocId)
Indexe Es wird jeweils ein Index über die Felder DocId und Value gebildet.
5.3
Anfrageprozessor
Der Anfrageprozessor koordiniert den Ablauf der Anfrage. Er nimmt die Anfrage von der Oberfläche
entgegen und läßt vom Anfrageübersetzer eine SQL-Anfrage generieren. Daraufhin führt er die Anfrage
an die Datenbank aus und übergibt dem Dokumentenerzeuger die Ergebnistupel der SQL-Anfrage.
5.4
Anfrageübersetzer
Der Anfrageübersetzer generiert mit Hilfe des vorgestellten Algorithmus aus der XML-QL Anfrage
ein SQL-Statement. Der Algorithmus ist in der Implementierung an die erweiterten Tabellenstrukturn
angepaßt.
5.5
Dokumenterzeuger
Der Dokumenterzeuger erstellt mit Hilfe des vorgestellten Algorithmus und der Ergebnistupel der SQLAnfrage das Ergebnisdokument der XML-QL Anfrage.
26
5.6
Dokument Import
Der Dokumentimport importiert ein XML-Dokument mit Hilfe des beschriebenen Algorithmus in die
Datenbank. Der Import wird über die JDBC-Schnittstelle realisiert.
6
Installation
Die Installationsdatein sind in vier Verzeichnisse aufgeteilt.
install/jaxp/ In diesem Verzeichnis befindet sich das JAXP-Paket von SUN. Dieses Paket beinhaltet
den benutzen SAX-Parser.
install/src/ In diesem Verzeichnis befinden sich Programmquellen und Installationsskripts in einer
Zip-Datei.
install/sql/ In diesem Verzeichnis befindet sich das SQL-Skript zum Erstellen der Datenbanktabellen
und Indexe.
install/doc/ In diesem Verzeichnis befindet sich die TEX-Quellen und Bilder dieses Dokumentes.
Nun werden die einzelnen Schritte der Installation beschrieben.
1.Vorrausetzungen: Der Benutzer muß einen Account für den Oracleserver des Institutes B der Universität Hannover und die Rechte besitzen, Tabellen anlegen, verändern und löschen zu können.
Weiterhin muß das JAXP-Packet korrekt laut Installationsanleitung von SUN installiert sein,
ebenso wie die Klassenbibliothek des Institutes.
2.Anlegen der Tabelle: Nachdem alle Vorraussetzungen erfüllt sind, muß das SQL-Script xmlqldb.sql
ausgeführt werden.
3.XML-QL Engine Aus dem Verzeichnis install/src muß die Datei xmlql.zip in das gewünschte Zielverzeichnis entpackt werden. Es ist darauf zu achten ,daß sich das Zielverzeichnis im CLASSPATH
befindet. Nun muß das Script buildall.sh 9 ausgeführt werden. Das Programm kann mit Hilfe des
Skriptes xmlql.sh aus dem Zielverzeichnis gestartet werden.
9 Das
Skript wird in das angegebene Zielverzeichnis entpackt
27
7
7.1
Benutzerhandbuch
Start des Programmes
Nach erfolgreicher Installation kann das Programm durch Aufrufen des Skripts xmlql.sh gestartet werden. Nachdem das Programm geladen wurde, wird der Benutzer aufgefordert den Username, die Datenbank und sein Password einzugeben, um sich an der Datenbank anzumelden.
7.2
Importieren eines XML-Dokumentes
Unter dem Menüpunkt File-Import kann der der Import ausgewählt werden. Der Benutzer wird daraufhin aufgefordert, über eine Dialogauswahlbox die zu importierende Datei anzugeben. Danach wird
der Import gestartet.
7.3
Laden einer Anfrage
Unter dem Menüpunkt Query-load kann eine Anfrage über eine Dialogauswahlbox geladen werden. Die
Dateien haben im Regelfall die Endung .xmlql. Wenn das Laden der Anfrage erfolgreich war, wird diese
im Anfragefenster vorgeblendet.
7.4
Speichern einer Anfrage
Unter dem Menüpunkt Query-save kann eine Anfrage über eine Dialogauswahlbox gespeichert werden.
Der Benutzer wird dabei aufgefordert, einen Dateinamen anzugeben.
7.5
Ausführen einer Anfrage
Unter dem Menüpunkt Query-execute kann eine Anfrage ausgeführt werden. Fehlermeldungen werden
dem Benutzer im Meldungsfenster angezeigt. Falls das Ergebnis der Anfrage in eine Datei geschrieben
werden soll, wird der Benutzer über eine Dialogauswahlbox zur Eingabe eines Dateinamens aufgefordert.
7.6
Auswahl der Ausgabeart
Unter dem Menpunkt Option-send to kann das Ziel der Ausgabe über Radiobuttons eingestellt werden.
Entweder wird das Ergebnis in eine Datei geschrieben oder im Ergebnisfenster angezeigt.
8
Erfahrungen und Ausblicke
Verarbeitung großer XML-Dokumente Bei Probeläufen mit einer großen Datenbank (Tabelle mit
mehr als 1.000.000 Zeilen) konnten keine nennenswerten Verschlechterungen der Geschwindigkeit
festgestellt werden. Ein Großteil der Anfragezeit wurde für das Schreiben des Ergebnisdokumentes benötigt. Dabei wurden Indexe über die Felder tblEdge(Name,TargetId), tblEdge(SourceId),
tblEdge(LeafId), tblEdge(AttrID) und tblEdge(DocId) verwendet.
Erweiterungen der Implementierung Das Verfolgen von Referenzen im Where-Abschnitt kann durch
die Einführung einer Hashtabelle beim Einlesen der Daten implementiert werden. Die Hashtabelle
verwaltet die Beziehung zwischen der internen, von der Datenbank vergebene Id, und den externen, als Attribut Id vorhandenen, Id eines Elementes. Trifft der Importalgorithmus auf ein
Attribut des Typs IDREF oder IDREFS wird anhand der Hashtabelle die externe Id in die interne Id übersetzt und als ZielId in die Kantenrelation geschrieben. Dieser Algorithmus funktioniert
allerdings nur ,falls eine DTD vorhanden ist, und eine Referenz sich auf eine ID bezieht, die schon
vorher im Dokument definiert wurde.
28
Falls eine Schachtelung der Anfragen möglich sein soll, muß für jedes Teilanfrageergenis eine Art
Datenbankview erstellt werden. Die jetzige Implementierung erzeugt direkt aus den Ergebnistupeln der SQL-Anfrage das Ergebnisdokument, man müßte also einen Zwischenschritt einbauen, der
aus den Ergebnistupeln der SQL-Anfrage eine temporäre Kantentabelle erzeugt und dann aus der
Kantentabelle erst das XML-Ergebnisdokument. Mit einer solchen Tabelle kann eine Schachtelung
leicht realisiert werden.
Es gibt in XML-QL ein Konstrukt, das einen Outer Join in relationalen Datenbanken entspricht.
Dabei werden zwei Anfrageblöcke mit einer Joinvariable erzeugt.
CONSTRUCT <result>
{ WHERE
...
<join>$a</join>
...
CONSTRUCT ... }
{ WHERE
...
<join>$a</join>
...
CONSTRUCT ... }
</result>
Dieses Feature ist ebenfalls leicht über temporäre Kantenrelationen zu implementieren.
9
9.1
Anhang A ,SQL-Scripts
Tabellen
Tabelle tblEdge
create table tblEdge (
SourceId
int
not null,
TargetId
int
null,
LeafId
int
null,
AttrId
int
null,
DocId
int
not null,
EdgeName
char(30)
not null,
Type
char(4)
not null,
Depth
smallint
not null
);
alter table tbledge
add constraint pk_tbledge primary key (SourceId,TargetId);
create index idx_SourceId
on tblEdge(SourceId);
create index idx_EdgeName_TargetId
on tblEdge(EdgeName,TargetId);
create index idx_LeafId
on tblEdge(LeafId);
29
create index idx_AttrId
on tblEdge(AttrId);
create index idx_DocId
on tblEdge(DocId);
Tabelle tblDocs
create table tblDocs (
DocId
int
not null,
url
varchar(255) null
);
alter table tblDocs
add constraint pk_tbldocs primary key (DocId);
Tabelle tblAttrs
create table tblAttrs (
AttrId
int
not null,
Value
varchar(255) null
);
alter table tblAttrs
add constraint pk_tblattrs primary key (AttrId);
create index idx_Attrs_Value
on tblAttrs(Value);
Tabelle tblLeafs
create table tblLeafs (
LeafId
int
not null,
Value
varchar(255) null
);
alter table tblleafs
add constraint pk_tblleafs primary key (leafid);
create index idx_Leafs_Value
on tblLeafs(Value);
9.2
Sequenzen
Sequenz SEQ SOURCEID
CREATE SEQUENCE seq_SourceId
INCREMENT BY 1
START WITH 1
NOMAXVALUE
NOCYCLE
CACHE 10;
Sequenz SEQ LEAFID
CREATE SEQUENCE seq_LeafId
INCREMENT BY 1
START WITH 1
NOMAXVALUE
NOCYCLE
CACHE 10;
30
Sequenz SEQ ATTRID
CREATE SEQUENCE seq_AttrId
INCREMENT BY 1
START WITH 1
NOMAXVALUE
NOCYCLE
CACHE 10;
Sequenz SEQ DOCID
CREATE SEQUENCE seq_DocId
INCREMENT BY 1
START WITH 1
NOMAXVALUE
NOCYCLE
CACHE 10;
9.3
Funktionen
Funktion getNextSourceId
CREATE OR REPLACE FUNCTION getNextSourceId RETURN int
AS
New_SourceId int;
BEGIN
SELECT seq_SourceId.nextval INTO New_SourceId FROM dual;
RETURN (New_SourceId);
END;
Funktion getNextLeafId
CREATE OR REPLACE FUNCTION getNextLeafId RETURN int
AS
New_LeafId int;
BEGIN
SELECT seq_LeafId.nextval INTO New_LeafId FROM dual;
RETURN (New_LeafId);
END;
Funktion getNextAttrId
CREATE OR REPLACE FUNCTION getNextAttrId RETURN int
AS
New_AttrId int;
BEGIN
SELECT seq_AttrId.nextval INTO New_AttrId FROM dual;
RETURN (New_AttrId);
END;
Funktion getNextDocId
CREATE OR REPLACE FUNCTION getNextDocId RETURN int
AS
New_DocId int;
BEGIN
SELECT seq_DocId.nextval INTO New_DocId FROM dual;
RETURN (New_DocId);
END;
31
Literatur
[1] Alin Deutsch, Mary Fernandez, Daniela Florescu, Alon Levy and Dan Suciu XML-QL: a query
Language for XML. In Proc of the Int. WWW Conf., 1999
[2] Mary Fernandez Beispielimplementierung der XML-QL Anfragesprache,
http://www.research.att.com/˜mff/xmlql
[3] Daniela Florescu and Donals Kossmann Storing and Querying XML Data Using an RDBMS, Bulletin of the Technical Commitee on Data Engineering, September 1999.
[4] Daniela Florescu and Donald Kossmann A Performance Evaluation of Alternative Mapping Schemes for Storing XML Data in a relational Database, INRIA Rapport de recherche, Mai 1999.
[5] Alfred V. Aho, Ravi Sethi, Jeffrey D. Ullmann Compilerbau, Addison Wesley Deutschland
[6] N. Wirth Compilerbau, Teubner Studienbucher Informatik
[7] Erich Gamma et al. Design Patterns, Addison Wesley Professional Computing Series
32
Herunterladen