XML: Von Datenbank zu Datenbank

XML-Dateien bieten die Möglichkeit, Daten in hierarchischer Struktur im Textformat abzulegen. Die daraus entstehenden Dateien liefern im Wesentlichen eine Möglichkeit zum Austauschen von Daten. Dieser Beitrag zeigt, wie Sie dieses Format zum Austauschen oder Sammeln von Daten zwischen Access-Datenbanken mit identischem Datenmodell einsetzen.

XML als Austauschformat

Den Einsatz von XML als Datenaustauschformat rechtfertigen einige Szenarios. In den meisten Fällen ist dabei Maßarbeit angesagt: Es kann beispielsweise sein, dass eine andere Anwendung eine Spezifikation bereitstellt, die das Format zu importierender XML-Daten definiert. Die Wahrscheinlichkeit, dass Access – egal in welcher Version – den Export automatisch im gewünschten Format vornimmt, ist gering. Also legen Sie selbst Hand an und erzeugen entweder direkt mit der XML-Bibliothek von Microsoft ein entsprechendes XML-Dokument oder Sie schneiden die von Access ausgegebene Datei auf die Zielanwendung zu.

Genauso kann es auch andersherum geschehen: Eine externe Anwendung liefert Daten in einem bestimmten XML-Schema, die Sie gern in Ihre Access-Datenbank importieren möchten. Auch hier können Sie die Daten per XSL entsprechend modifizieren oder direkt eine passende VBA-Routine entwickeln, die aus der Ausgangsdatei die benötigten Daten herausliest.

Unter Umständen sind die Ziel- und die Quellanwendung identisch – zumindest in Bezug auf das Datenmodell: So könnte es beispielsweise sein, dass Außendienstmitarbeiter bei Kundenbesuchen oder daheim am Telefon Daten zu Kunden oder Bestellungen aufnehmen. Zum Synchronisieren der Daten mit der zentralen Datenbank, die etwa auf einem Rechner in der Geschäftsstelle liegt, gibt es dann verschiedene Wege – beispielsweise das direkte Schreiben der Daten über eine passende ODBC-Verbindung.

Ist die Menge der Daten überschaubar, kann aber auch eine XML-Datei als Träger der auszutauschenden Informationen herhalten – zum Beispiel als Inhalt einer E-Mail oder als Anhang einer solchen. Natürlich kann man solche XML-Dateien auch per FTP oder mit einem anderen Protokoll über einen Webserver austauschen.

Der zuletzt geschilderte Fall steht in diesem Beitrag im Mittelpunkt: Aus einer Datenbank sollen zunächst die Daten einer oder mehrerer Tabellen in eine XML-Datei exportiert und dann in eine weitere Datenbank mit gleichem Aufbau importiert werden. Prinzipiell sind damit natürlich auch die ersten beiden Varianten abgedeckt – immerhin benötigen Sie hier ja jeweils einen Export, der auf das von der Zielanwendung benötigte XML-Schema abzielt und umgekehrt.

Beispieldatenbank

Als Beispieldatenbank dient die modifizierte Nordwind-Datenbank. Modifiziert deshalb, weil die bei den meisten Entwicklern gängige Konvention für die Benennung von Tabellen und Feldern angewendet wurde.

Sie enthält neben den üblichen Tabellen auch noch eine Kopie aller Tabellen, deren Name um den Zusatz 1 erweitert ist – auf diese Weise benötigen Sie zum Experimentieren mit den Beispielen dieses Beitrags nicht mehrere Datenbanken.

Von der Tabelle in das XML-Dokument

Die Abbildung einfacher Tabellen in XML-Dokumenten ist nicht besonders schwierig. Die Tabelle aus Abb. 1 etwa ließe sich beispielsweise so abbilden:

<Kontakte>
 <Kontakt>
    <KontaktID>1</KontaktID>
    <Vorname>André</Vorname>
    <Nachname>Minhorst</Nachname>
    <Telefon>0203-4494477</Telefon>
 </Kontakt>
 <Kontakt>
    ...
 </Kontakt>
</Kontakte>
pic001.tif

Abb. 1: Eine einfache, als XML-Dokument abzubildende Tabelle

Dabei entspricht jeder Datensatz einem Kontakt-Element und jedes Feld einem weiteren Element mit einem Text-Wert.

Es gibt noch weitere Varianten, Daten aus Tabellen in XML-Dokumenten unterzubringen. Dabei entspricht wiederum je ein Kontakt-Element einem Datensatz, allerdings werden die Feldinhalte nun nicht in eigenen Elementen, sondern in Eigenschaften des Kontakt-Elements gespeichert:

<Kontakte>
 <Kontakt KontaktID="1" Vorname="André" 
Nachname="Minhorst" Telefon="0203-4494477"/> <Kontakt KontaktID="2" Vorname="Sascha"
Nachname="Trowitzsch" Telefon="030-1234566"/> </Kontakte>

Die beiden Varianten lassen sich auch derart kombinieren, dass die Geschäftsdaten in eigenen Elementen und die ID, die nur der eindeutigen Identifizierung des Datensatzes dient, in einer Eigenschaft gespeichert werden:

<Kontakte>
 <Kontakt ID="1">
    <Vorname>André</Vorname>
    <Nachname>Minhorst</Nachname>
    <Telefon>0203-4494477</Telefon>
 </Kontakt>
 <Kontakt ID="2">
    <Vorname>Sascha</Vorname>
    <Nachname>Trowitzsch</Nachname>
    <Telefon>030-1234566</Telefon>
 </Kontakt>
</Kontakte>

Daneben gibt es sicher noch viel allgemeinere Schemata für das Speichern von Tabelleninhalten in XML-Dateien. Diese sollen jedoch aus Platzgründen hier nicht näher beleuchtet werden.

1:n-Beziehungen

Ein wenig interessanter wird es, wenn Beziehungen und damit verknüpfte Daten ins Spiel kommen. Wie stellt man beispielsweise eine 1:n-Beziehung in einem XML-Dokument dar Erweitern wir das obige Beispiel um eine kleine Tabelle namens tblAnreden, die zwei Felder namens AnredeID und Anrede enthält und die von der Tabelle tblKontakte über das Fremdschlüsselfeld AnredeID referenziert wird.

Eindeutige Daten

Wann immer Daten nicht nur in einer, sondern über mehrere, verteilte Datenbanken eindeutig identifizierbar sein sollen, brauchen Sie entsprechende Primärschlüssel. Mit hoher Wahrscheinlichkeit eindeutig sind Globally Unified Identifier (GUIDs). Sie erzeugen diese mit Hilfe zweier API-Funktionen und einem entsprechenden Wrapper, den Sie unter dem Namen CreateGUID im Modul mdlGlobal der Beispieldatenbank finden.

Das Anpassen einer bestehenden Datenbank auf GUIDs als Primärschlüssel ist eine nicht besonders komplizierte Fleißarbeit. Beim Zusammenführen von Daten aus verschiedenen Datenbanken ist dies aber unerlässlich: Sie können auf diese Weise genau feststellen, ob ein Datensatz bereits vorhanden ist und angepasst werden muss oder ob dieser komplett neu zu erstellen ist. Auch die in Access eingebaute Replikation arbeitet auf diese Weise.

Probleme

Beim Export von Daten in eine XML-Datei und beim anschließenden kompletten Import in eine gleich aufgebaute Datenbank tritt das eine oder andere kleinere Problem auf – wer schon einmal Daten von Excel nach Access transportiert hat oder umgekehrt, kennt das vermutlich. Beim Erstellen der Routinen zum Weitergeben der Daten der Südsturm-Datenbank sind beispielsweise folgende Probleme aufgetreten:

  • Die Binärdaten lassen sich nicht als Inhalt einfacher Elemente weitergeben.
  • Zeilenumbrüche (Chr(13) + Chr(10)) wurden in Chr(10) umgewandelt, was in Tabellen und Formularen der Zieldatenbank nicht mehr richtig angezeigt wurde.
  • Zahlen mit Dezimalteil wurden nur als Text ordnungsgemäß weitergegeben, weil so das Komma als Dezimalzeichen beibehalten wurde. Beim Speichern mit nodeTypedValue wurde dieses in einen Punkt umgewandelt, der in der Zieldatenbank nicht als Dezimalzeichen erkannt wird.
  • Nullwerte in Feldern der Tabelle lösten beim Einfügen über die Eigenschaft text Fehler aus.

Die Datentypen in XML-Dateien liefert übrigens die Referenz aus [1] unter MSXML|XML Standards Preference|XDR Reference|XDR Schema Data Types Reference|XDR Schema Data Types. Wie die oben gefundenen Probleme behoben werden, erfahren Sie in den folgenden Abschnitten.

Komplette Datenbank exportieren

Für das Exportieren beliebiger Datenbanken ist lediglich die Routine aus Listing 1 nötig. Sie erledigt alle notwendigen Schritte, indem sie zunächst die Zeile mit den Angaben zu Format und Codierung erzeugt und dann in verschachtelten For Each– und Do While-Schleifen die Tabellen, die Datensätze, die Felder und Werte durchläuft und in Form geeigneter XML-Elemente zum DOMDocument-Objekt hinzufügt. Voraussetzung für den Einsatz dieser Routine ist, dass alle zu berücksichtigenden Tabellen mit dem Präfix tbl beginnen – das ist aber bei dieser Datenbank der Fall.

Listing 1: Tabellen in ein XML-Dokument exportieren

Public Sub TabellenExportieren()

' … Deklaration aus Platzgründen nicht abgedruckt

Set db = CurrentDb

Set objXML = New DOMDocument

AddFormat objXML, eEncodingUTF8

Set nodeRoot = objXML.createElement("Datenbank")

strTableNames = ExportOrder

For i = LBound(strTableNames) To UBound(strTableNames)

strTablename = strTableNames(i)

If Left(strTablename, 3) = "tbl" Then

Set rst = db.OpenRecordset("SELECT * FROM " & strTablename, dbOpenDynaset)

Do While Not rst.EOF

Set nodeTable = objXML.createElement(strTablename)

nodeTable.setAttribute "Tabellenname", strTablename

For Each fld In rst.Fields

Set nodeField = objXML.createElement(fld.Name)

Select Case fld.Type

Case dbLongBinary

nodeField.DataType = "bin.base64"

nodeField.nodeTypedValue = fld.Value

Case dbDate

nodeField.DataType = "date"

nodeField.nodeTypedValue = fld.Value

Case dbBoolean

nodeField.nodeTypedValue = rst(fld.Name).Value

Case dbBigInt, dbBinary, dbByte, dbDecimal, dbDouble, dbFloat, dbInteger, _

dbLong, dbNumeric, dbSingle, dbCurrency

nodeField.DataType = "float"

nodeField.nodeTypedValue = fld.Value

Case dbChar, dbText, dbMemo

nodeField.DataType = "string"

nodeField.nodeTypedValue = fld.Value

Case Else

Debug.Print fld.Name, fld.Type

nodeField.nodeTypedValue = Nz(rst(fld.Name).Value, "")

Sie haben das Ende des frei verfügbaren Textes erreicht. Möchten Sie ...

Workplace

Jahresabonnement TestzugangOder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar