XML: Von Datenbank zu Datenbank

Lies diesen Artikel und viele weitere mit einem kostenlosen, einwöchigen Testzugang.

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 Bild 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

Bild 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, "")

Die Routine enthält einige weitere Finessen: So werden die Tabellen beispielsweise nicht in einer willkürlichen, sondern in einer durch eine weitere Funktion festgelegten Reihenfolge durchlaufen – dazu später mehr.

Des Weiteren schreibt die Routine nicht einfach alle Daten als Text in die jeweiligen Objekte, sondern prüft zuvor den Datentyp des Feldes und schreibt die Daten unter Angabe gewisser Datentypinformationen in das XML-Dokument. Wichtig ist dies vor allem, damit der Inhalt von OLE-Objekten, von Boolean- und Datumsfeldern und von Feldern mit Dezimalzahlen korrekt wieder hergestellt werden kann.

Import komplexerer Daten

Sie haben nun mit einer recht einfachen Routine alle Daten der Südsturm-Datenbank in ein XML-Dokument geschrieben – scheinbar mit allen Informationen, die für das Zurückschreiben in eine Datenbank mit gleichem Datenmodell nötig sind.

Leider sind die Informationen doch nicht ganz vollständig und der Import wird nur mit viel Glück reibungslos über die Bühne gehen – zumindest, wenn die Zieldatenbank dieselben Beziehungen wie die Quelldatenbank aufweist. Diese legen nämlich in gewissem Maße die Reihenfolge des Imports von Daten fest. So können Sie beispielsweise nicht die Daten von Tabellen einlesen, deren Fremdschlüsselfelder auf die Daten in Tabellen verweisen, die zuvor noch nicht gefüllt wurden, wenn referenzielle Integrität vorgesehen ist.

Wenn Sie also etwa die Bestellungen aus der XML-Datei in die Tabelle tblBestellungen schreiben möchten, löst dies einen Fehler etwa mit folgender Meldung aus: “Der Datensatz kann nicht hinzugefügt oder geändert werden, da ein Datensatz der Tabelle “tblKunden’ mit diesem Datensatz in Beziehung stehen muss.”

Sie brauchen also Informationen darüber, in welcher Reihenfolge die Tabellen beim Import bearbeitet werden sollen. Wenn man das Datenmodell betrachtet, lassen sich die einzelnen Schritte recht leicht ableiten: Die Tabellen tblPersonal, tblLieferanten, tblKategorien und tblVersandfirmen besitzen beispielsweise gar keine Fremdschlüsselfelder und können direkt zu Beginn in beliebiger Reihenfolge eingelesen werden. Dann folgen die Tabellen tblArtikel und tblBestellungen, die beide ausschließlich Fremdschlüssel aufweisen, die auf die bereits aufgeführten Tabellen zeigen. Die Tabelle tblBestelldetails referenziert ihrerseits weitere Tabellen, wird aber von keiner der anderen Tabellen referenziert und somit als letzte importiert.

Nun erfolgt der Export der Daten in das XML-Dokument innerhalb einer Routine, die selbst keine einzige der betroffenen Tabellen oder Felder namentlich referenziert und daher auch mit Tabellen anderer Datenbanken funktionieren würde – vorausgesetzt, diese genügen der in der Export-Prozedur geforderten Konvention nach Tabellennamen, die mit tbl beginnen (die Prozedur ließe sich aber auch an andere Tabellennamen anpassen). Da wäre es doch schön, wenn der Import in die Zieldatenbank auf genauso flexible Weise erfolgen könnte.

Die richtige Export-Reihenfolge

Sie müssen also vor dem Import mit einem geeigneten Algorithmus die Reihenfolge der zu importierenden Tabellen ermitteln oder – noch besser – die Tabellen direkt in der richtigen Reihenfolge in die XML-Datenbank schreiben.

Die nachfolgend beschriebene Routine, deren kompletten Code Sie in der Beispieldatenbank im Modul mdlXML unter dem Namen ExportOrder finden, erledigt diese Aufgabe und liefert als Ergebnis ein Array mit den Namen der Tabellen in der richtigen Reihenfolge.

Tabellen ohne Fremdschlüssel finden

Im ersten Schritt benötigen Sie alle Tabellen, die nicht auf andere Tabellen verweisen. Beim Auffinden dieser Tabellen helfen die Systemtabellen von Access: Die Tabelle MSysObjects verzeichnet alle Tabellen (und auch alle übrigen Objekte einer Datenbank) und die Tabelle MSysRelationships Informationen über die Beziehungen zwischen den Tabellen.

Die Routine aus Listing 2 füllt zunächst ein Array namens strTables mit den Namen der in der Datenbank enthaltenen Tabellen, die mit tbl beginnen.

Listing 2: Sortieren der Tabellen einer Datenbank in eine Reihenfolge, in der Tabellen mit Fremdschlüsselfeldern erst nach dem Anlegen der Datensätze der verknüpften Tabellen gefüllt werden.

Public Function ExportOrder() As Variant

Dim strTables() As String

Dim db As DAO.Database

Dim intTable As Integer

Dim intReferencedTable As Integer

Dim rstTables As DAO.Recordset

Dim rstRelations As DAO.Recordset

Dim intTables As Integer

Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

Testzugang

eine Woche kostenlosen Zugriff auf diesen und mehr als 1.000 weitere Artikel

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar