Donnerstag, 4. Dezember 2008





April 2006
aus XML & Web Services Magazin Ausgabe: 5.2003
Von SQL nach XML
Migration einer MySQL-Anwendung auf ein XML-System
von Heiko Weber

Die meisten Anwendungen nutzen heute ein relationales Datenbanksystem. Immer häufiger wird jedoch XML als universelles Austauschformat eingesetzt, das dann auch in Verbindung mit einem speziellen XML-Server oder einer XML-Datenbank zum Einsatz kommt. Wie sich eine vorhandene MySQL-Anwendung auf die Verwendung mit einem XML-Server umstellen lässt, zeigt der folgende Beitrag.


Ausgangssituation für das Projekt ist ein in PHP programmiertes Webforum, das bislang mit einer MySQL-Datenbank arbeitete. Das Forum sollten Entwickler der Software AG zum Informationsaustausch mit Kollegen an anderen Standorten nutzen. Um die gesammelten Erfahrungen auch anderen Anwendungen zugänglich zu machen, sollten die Einträge und Code-Beispiele als XML-Dokumente gespeichert werden. Mit Hilfe der Skriptsprache PHP waren die Umstellung auf XML sowie die Verwendung des Tamino XML-Servers recht einfach zu realisieren. In der Praxis funktioniert dieses Verfahren auch mit anderen Anwendungen.

Warum XML?
Wird XML zum Speichern der Forumsbeiträge genutzt, bleibt die ursprüngliche Struktur der Dokumente erhalten. Dies vereinfacht die Weiterverarbeitung in anderen Applikationen. Außerdem können eine Vielzahl von standardisierten XML-Verfahren wie XSLT (Stylesheets), XQuery etc. auf die Daten angewandt werden. Wenn diese Daten noch mit einem passenden XML Schema versehen werden, sind sie auch extrem portabel und sollten sich dann in jedem beliebigen XML-System verarbeiten lassen.

Konvertierung von relationalen Tabellen nach XML Schema
Der erste Schritt bei der Anpassung einer Applikation von einem relationalen Speichermodell hin zu XML ist die Konvertierung der Speicherstrukturen. In relationalen Datenbanksystemen werden die Daten in Tabellen gespeichert. Die Speichersicht in XML ist ein Baum bzw. ein Graph. In XML-Datenbanksystemen wird die Speicherstruktur normalerweise über DTDs oder XML Schemas definiert. Der Tamino XML-Server verwendet standardkonforme XML Schemas und nutzt den Erweiterungsmodus von XML Schema (xs:annotation),
um Tamino-spezifische Informationen wie zum Beispiel Indizes zu definieren.

Grundsätzlich ergeben sich zwei Möglichkeiten, wie die relationalen Datenstrukturen in ein XML-Modell konvertiert werden können, wenn das Datenformat größtenteils unverändert übernommen werden soll: Entweder es wird genau ein XML-Dokument pro Tabellenspalte erstellt oder die kompletten Daten einer Tabelle werden zu einem einzigen XML-Dokument zusammengefasst. Je nach Implementierung der internen Speicherung kann es bei einigen XML-Datenbanksystemen Performancevorteile bringen, wenn genau ein XML-Dokument pro Spalte generiert wird.

Im vorliegenden Beispiel des Forums sollte die Anwendung mit möglichst wenig Aufwand an die Anforderungen von XML angepasst werden. Daher wurde die relationale Struktur direkt nach XML konvertiert, sodass eine Tabellenspalte genau einem XML-Dokument entspricht. man musste also nur überlegen, welche Informationen gut zu einem Element zusammengruppiert werden könnten und ob diese als Attribut eines Elements oder eher als Unterelement eines anderen Elements dargestellt werden sollten. Tabelle 1 zeigt die Tabellenstruktur, wie sie in der MySQL-Anwendung verwendet wurde.

Da die textuelle Form des XML Schemas sehr umfangreich ist, soll hier nur eine grafische Darstellung gezeigt werden, wie sie im GUI-basierten Schema-Editor von Tamino erscheint (siehe Abb. 1). Die rechteckigen Kästen mit einer 1, einem ? oder einem * bezeichnen XML-Elemente, die Dreiecke stellen Attribute dar. Sequence und Choice sind Konstrukte von XML Schema, mit denen Gruppen von Elementen modelliert werden.


Abb. 1: XML Schema für die Forumseinträge


Die Fragezeichen symbolisieren optionale Elemente. Das Element rootNodeInfos beinhaltet beispielsweise Daten, die nur im ersten Posting eines Threads gespeichert werden sollen, weshalb dieses Element als optional definiert wurde. Eine 1 symbolisiert, dass das Element genau einmal vorkommen muss. Ein Stern (*) steht für ein beliebig häufiges Vorkommen. So dürfen in als Inhalt des Elements
contents, in dem der eigentliche Inhalt des Postings gespeichert wird, beliebig viele weitere Elemente vorkommen. Dies ermöglicht es, dass XML auch innerhalb des Postings eingesetzt werden kann, um zum Beispiel die Formatierung des Textes zu definieren.

Das Beispiel sieht in XML folgendermaßen aus:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<iwfForum position="1.0" reid="0" rootid="1" thisid="1">
<datetimeAdded>2003-06-18T09:06:40.000+02:00</datetimeAdded>
<username>heiko</username>
<realname>Heiko Weber</realname>
<title>Ein kleiner Test-Thread</title>
<contents><b>Testbeitrag</b> im Forum.</contents>
<rootNodeInfos>
<numPostings>1</numPostings>
<datetimeLastAdded>2003-06-18T09:06:40.000+02:00</datetimeLastAdded>
</rootNodeInfos>
</iwfForum>

XML-Queries
Im ersten Schritt wurde gezeigt, wie die Datenstrukturen in einer XML-Datenbank aussehen. Das Abspeichern der Daten erfolgt, je nach Datenbanksystem, mit einem einfachen Speichern der XML-Dokumente in die vorgesehenen Container. In Tamino sind diese mit Collections bezeichnet. Sind die Daten erst einmal in der Datenbank gespeichert, gibt es verschiedene Mechanismen, um sie wieder auszulesen. Tamino unterstützt hierfür die Abfragesprachen X-Query und Query.

X-Query-Anfragen
X-Query entspricht im wesentlichen XPath, wie es auch in XSLT verwendet wird, mit einigen Erweiterungen, um beispielsweise das Sortieren von Ergebnismengen zu ermöglich. Diese Sprache ist sehr einfach anwendbar: Im wesentlichen werden Pfade im XML-Dokument formuliert und mit speziellen Filtern erweitert, um die gewünschten Dokumente zu finden. Leider ist diese Abfragesprache in ihrer Ausdrucksform eingeschränkt und es ist ausschließlich das Auslesen der Daten möglich.

XQuery-Anfragen
Stand der Technik ist die Abfragesprache XQuery. Sie ist zwar immer noch ein Working Draft des W3C, gibt sich aber schon ziemlich ausgereift. Auch sind bereits zahlreiche Implementierungen verfügbar. Ein SQL-Anwender, der sich in XQuery eingearbeitet hat, wird dort nichts vermissen. Mit XQuery sind in Tamino neben den lesenden Queries auch Update-Queries möglich, die Inhalte in XML-Dokumenten verändern oder neue Daten einfügen.

Da in dem Beispiel des Forums oft nur sehr einfache Queries gemacht wurden, in denen jeweils ein komplettes XML-Dokument unverändert zurückgegeben werden sollte, wurde für die lesenden Queries X-Query eingesetzt. Beispielsweise wurde folgende Abfrage eingesetzt, um alle XML-Dokumente zu finden, die den Anfang eines Diskussions-Threads darstellen:

/iwfForum[@reid="0"] sortby(rootNodeInfos/datetimeLastAdded desc)

Mit dem Einsatz der PHP Tamino API (enthalten auf der beiliegenden CD) wird als Ergebnis dieser Query ein DOM-Baum zurückgeliefert, der die kompletten Ergebnis-Dokumente beinhaltet. Dieser DOM-Baum kann mit Hilfe der in PHP enthaltenen DOM-Funktionen durchlaufen und die gewünschten Informationen aus dem Baum angezeigt werden. Listing 2 zeigt die Umsetzung in PHP.

Listing 2

$tamino->query("/iwfForum[@reid=\"0\"] sortby(rootNodeInfos/datetimeLastAdded desc)");
$domnodeResultElement = $tamino->getResultDomNode();
if ($domnodeResultElement) {
$domnodeCurrent = $domnodeResultElement->first_child();
while ($domnodeCurrent != NULL) {
if ($domnodeCurrent->node_type() == XML_ELEMENT_NODE) {
if ($domnodeCurrent->node_name() == "iwfForum") {
// get attribute values
$nodelistAttributes = $domnodeCurrent->attributes();
$numAttributes = count($nodelistAttributes);
for ($i = 0; $i < $numAttributes; $i++) {
if ($nodelistAttributes[$i]->name() == "thisid")
$entryId = intVal($nodelistAttributes[$i]->value());
}
// get element values
$domnodeCurrent2 = $domnodeCurrent->first_child();
while ($domnodeCurrent2 != NULL) {
if ($domnodeCurrent2->node_type() == XML_ELEMENT_NODE) {
if ($domnodeCurrent2->node_name() == "title")
$entryTitle = $domnodeCurrent2->get_content();
else if ($domnodeCurrent2->node_name() == "realname")
$entryRealName = $domnodeCurrent2->get_content();
else if ($domnodeCurrent2->node_name() == "rootNodeInfos") {
$domnodeCurrent3 = $domnodeCurrent2->first_child();
while ($domnodeCurrent3 != NULL) {
if ($domnodeCurrent3->node_type() == XML_ELEMENT_NODE) {
if ($domnodeCurrent3->node_name() == "numPostings")
$entryNumPostings = intVal($domnodeCurrent3->get_content());
else if ($domnodeCurrent3->node_name() == "datetimeLastAdded")
$entryDatetimeLastAdded = $domnodeCurrent3->get_content();
}
$domnodeCurrent3 = $domnodeCurrent3->next_sibling();
}
}
}
$domnodeCurrent2 = $domnodeCurrent2->next_sibling();
}
}
// ** display thread information here ***
}
$domnodeCurrent = $domnodeCurrent->next_sibling();
}
}

XQuery-Update
Ein bereits erwähnter Vorteil von XQuery gegenüber X-Query besteht in der Möglichkeit, Daten verändern zu können. Mit Updates in XQuery lassen sich einzelne Teile eines XML-Dokuments verändern. In dem Forum-Beispiel wurden in der alten Version SQL-Updates geschickt. Für einen Thread wurde vermerkt, wie viele Beiträge insgesamt in dem Thread vorhanden sind.
Dabei wurde folgende Query verwendet:

UPDATE iwfForum SET numPostings=numPostings+1 WHERE thisid=n

In XQuery sieht dieses Update zum Beispiel wie folgt aus:

update for $a in input()/iwfForum where $a/@thisid=n
do replace $a/rootNodeInfos/numPostings
with <numPostings>{$a/rootNodeInfos/numPostings + 1}</numPostings>

Diese etwas unfangreichere Formulierung ist erst einmal gewöhnungsbedürftig, ermöglicht aber deutlich komplexere Update-Formulierungen, als sie in SQL möglich sind. Die Funktion input() ist in Tamino ein Mechanismus, um alle Dokumente einer Collection zu erhalten. Der Ausdruck input()/iwfForum liefert also alle XML-Dokumente, die das Root-Element iwfForum besitzen.

Die Vorteile in der Praxis
Einige der prinzipiellen Vorteile des Speicherns von XML-Dokumenten wurden schon kurz angesprochen. Für das Forum ergab sich, dass sich die Beiträge nun auch mit XML-Tags versehen und dann via Stylesheets bei der Ausgabe formatiert lassen. Die Volltextsuche von Tamino, aber auch vieler anderer XML-Datenbanken, kann XML-Dokumente flexibel bearbeiten. Die Suchfunktion lässt sich so definieren, dass beispielsweise die XML-Tags bei der Volltext-Indizierung ignoriert werden. Der Satz Dies ist ein Test. lässt sich zum Beispiel in der Form Dies ist ein <bold>Test</bold>. speichern. Eine Volltextsuche nach ein Test würde dann zu einem Treffer führen.

Da XML nicht flache Strukturen abbildet, wie dies bei relationalen Tabellen der Fall ist, lassen sich Daten benutzerfreundlicher strukturieren. Im Beispiel des Forums wurde der Knoten rootNodeInfos definiert. Dieser Knoten beinhaltet nur Informationen für die ersten Beiträge eines Threads und war deswegen als optional gekennzeichnet. In einer relationalen Tabelle hätte diese Information entweder
in eine separate Tabelle gespeichert werden müssen, oder jeder Eintrag hätte diese Information enthalten, obwohl sie bei den meisten Einträgen nicht erforderlich ist.

Wer selbst ein wenig mit einem XML-Datenbanksystem experimentieren möchte, kann sich die kostenlose Testversion des Tamino XML Servers im XML Starter Kit der Software AG herunterladen (www.xmlstarterkit.com).
Mit der PHP Tamino API auf der Heft-CD lassen sich dann XML-Applikationen sehr einfach realisieren. Heiko Weber gehört seit 3 Jahren zum Enwicklungsteam des Tamino XML Servers der Software AG. Zuvor hat er jahrelange Erfahrungen bei der Entwicklung von Web-Applikationen, hauptsächlich mit der Skriptsprache PHP, gesammelt.

Links und Literatur

Informationen zu Tamino XML-Server


    Hat Ihnen dieser Artikel gefallen? Dann abonnieren Sie das Entwickler Magazin direkt über unser Online-Formular.

zur vorherigen Seite
zurück
an den Anfang der Seite
nach oben
Diesen Artikel drucken
drucken
Diesen Artikel weiterempfehlen
empfehlen




Software & Support Verlag GmbH