XML-Export mit VBA

Dieser Artikel ist Teil des Magazins 'Access im Unternehmen', Ausgabe .

XML-Export mit VBA

Access stellt verschiedene Möglichkeiten für den Export von Daten im XML-Format zur Verfügung. Die Variante, mit der Sie Tabellen über die Benutzeroberfläche in das XML-Format exportieren können, können Sie natürlich auch per VBA nutzen – und zwar mit dem Befehl »ExportXML« des »Application«-Objekts. Dieser Beitrag zeigt, welcher Parameter welcher Option entspricht und welche zusätzlichen Features Sie per VBA erhalten.

Der Export von Daten aus Access heraus in ein XML-Dokument erfordert immer zumindest die Angabe einer Tabelle sowie der Zieldatei. Außerdem können Sie nicht nur Tabellen, sondern auch alle anderen Objekttypen von Access im XML-Format exportieren – also müssen Sie auch noch den Objekttyp angeben. Dementsprechend lautet die minimale Version eines Aufrufs der Methode ExportXML des Application-Objekts wie folgt:

Application.ExportXML acExportTable, "tblAnreden", _
    CurrentProject.Path & " blAnreden.xml"

Der erste Parameter erwartet den Objekttyp, in diesem Fall acExportTable (bei einer Abfrage würden Sie etwa acExportQuery nutzen). Der zweite gibt den Namen des zu exportierenden Objekts an (hier tblAnreden) und der dritte den Pfad zu der zu erzeugenden Datei. Hier haben wir CurrentProject.Path zur Ermittlung des Verzeichnisses der aktuellen Datenbank genutzt, damit die XML-Datei direkt in diesem Verzeichnis angelegt wird – und zwar unter dem Namen tblAnreden.xml. Damit können Sie den ersten einfachen Export per Einzeiler erledigen und sich das Ergebnis ansehen:

<?xml version="1.0" encoding="UTF-8"?>
<dataroot ...>
   <tblAnreden>
     <AnredeID>1</AnredeID>
     <Anrede>Herr</Anrede>
   </tblAnreden>
   <tblAnreden>
     <AnredeID>2</AnredeID>
     <Anrede>Frau</Anrede>
   </tblAnreden>
</dataroot>

Mit diesem Einzeiler sparen Sie sich einige Mausklicks, die Sie bei der Benutzung des Export-Assistenten über die Benutzeroberfläche hätten ausführen müssen – zumindest, wenn Sie diese Anweisung einmal in eine Prozedur eingetragen haben und dann aufrufen.

Nun bietet der Assistent noch einige weitere Möglichkeiten, die wir uns auch schon im Beitrag XML-Export ohne VBA (www.access-im-unternehmen.de/1045) angesehen haben. Diese wollen wir nun auch mit VBA abbilden.

Zu exportierende Daten einschränken

In manchen Fällen möchten Sie vielleicht nicht alle Daten einer Tabelle exportieren, sondern nur eine Teilmenge. Bei Benutzung des Assistenten musste dafür die Tabelle mit den zu exportierenden Daten geöffnet sein.

Wenn Sie einen einzelnen Datensatz exportieren wollten, mussten Sie diesen zunächst markieren und dann den Assistenten starten, der nun die Option Aktueller Datensatz bereitstellte. Wenn Sie zuvor einen Filter für die Tabelle oder Abfrage festgelegt haben, konnten Sie auch mit der Option Bestehenden Filter anwenden arbeiten.

Nun sollen Sie vor dem Exportieren der Tabellendaten nicht erst die Tabelle öffnen und den Filter definieren. Dies erledigen Sie nämlich mit einem einfachen Parameter der ExportXML-Methode. Im Gegensatz zu den bereits im vorherigen Beispiel vorgestellten drei Parametern befindet sich der nun gesuchte Parameter relativ weit hinten in der Parameterliste, sodass Sie entweder eine entsprechende Anzahl Kommata setzen, um zum gewünschten Parameter zu gelangen oder den Parameter benennen. Wir wollen in diesem Fall alle Datensätze der Tabelle tblArtikel exportieren, deren Artikelname mit A beginnt.

Im ersten Anlauf fügen wir die entsprechende Anzahl Kommata ein, wobei uns IntelliSense wie in Bild 1 unterstützt. Der Befehl sieht dann wie folgt aus:

Eingabe der Parameter für den Export mit einer Bedingung

Bild 1: Eingabe der Parameter für den Export mit einer Bedingung

Application.ExportXML acExportTable, "tblArtikel",  _
    CurrentProject.Path & " blArtikel.xml", , , , , ,  "Artikelname LIKE 'A*'"

Das Ergebnis überrascht: Es liefert nur den Kopf des Exportdokuments, aber keinerlei Artikeldaten (s. Bild 2). Eine kurze Prüfung der zu exportierenden Tabelle tblArtikel zeigt, dass dort durchaus Artikel vorliegen, deren Artikelname mit A beginnt. Ein Blick in die Online-Dokumentation liefert auch keine Hinweise auf einen Fehler in der Formulierung unserer Bedingung.

XML-Export ohne Daten

Bild 2: XML-Export ohne Daten

Also experimentieren wir einfach etwas herum und finden heraus, dass es mit kompletten Vergleichswerten funktioniert – also etwa mit folgendem Aufruf:

Application.ExportXML acExportTable, "tblArtikel",  _
    CurrentProject.Path & " blArtikel.xml", , , , , ,  "Artikelname LIKE 'Alice Mutton'"

Wie Bild 3 zeigt, funktioniert das Setzen einer Bedingung also grundsätzlich.

XML-Export mit Filter nach Artikelname

Bild 3: XML-Export mit Filter nach Artikelname

Woran also hapert es bei Verwendung eines Platzhalters wie dem Sternchen (*)?

Da wir wissen, dass in anderen SQL-Dialekten durchaus auch mal andere Platzhalter-Zeichen zum Einsatz kommen, wobei statt des Sternchens beispielsweise das Prozentzeichen (%) verwendet wird, probieren wir es einfach einmal so aus:

Application.ExportXML acExportTable, "tblArtikel", _
    CurrentProject.Path & " blArtikel.xml", , , , , ,  "Artikelname LIKE 'A%'"

Und siehe da: Es funktioniert! Hier ist die Ausgabe für diese Anweisung mit den beiden betroffenen Artikel-Datensätzen:

<?xml version="1.0" encoding="UTF-8"?>
<dataroot ...>
   <tblArtikel>
     <ArtikelID>3</ArtikelID>
     <Artikelname>Aniseed Syrup</Artikelname>
     <LieferantID>1</LieferantID>
     <KategorieID>2</KategorieID>
     <Liefereinheit>12 x 550-ml-Flaschen</Liefereinheit>
     <Einzelpreis>5</Einzelpreis>
     <Lagerbestand>13</Lagerbestand>
     <BestellteEinheiten>70</BestellteEinheiten>
     <Mindestbestand>25</Mindestbestand>
     <Auslaufartikel>0</Auslaufartikel>
   </tblArtikel>
   <tblArtikel>
     <ArtikelID>17</ArtikelID>
     <Artikelname>Alice Mutton</Artikelname>
     <LieferantID>7</LieferantID>
     <KategorieID>6</KategorieID>
     <Liefereinheit>20 x 1-kg-Dosen</Liefereinheit>
     <Einzelpreis>19.5</Einzelpreis>
     <Lagerbestand>0</Lagerbestand>
     <BestellteEinheiten>0</BestellteEinheiten>
     <Mindestbestand>0</Mindestbestand>
     <Auslaufartikel>1</Auslaufartikel>
   </tblArtikel>
</dataroot>

Wenn Sie nicht mit den vielen Kommata durcheinanderkommen wollen, können Sie, wie oben erwähnt, mit einem benannten Parameter arbeiten. Der Aufruf sieht dann so aus:

Application.ExportXML acExportTable, _
    "tblArtikel", CurrentProject.Path & " blArtikel.xml", _
    WhereCondition:="Artikelname LIKE 'A%'"

Sie können auch alle Parameter benennen:

Application.ExportXML ObjectType:=acExportTable,  DataSource:="tblArtikel", _
    DataTarget:=CurrentProject.Path & "	blArtikel.xml",  WhereCondition:="Artikelname LIKE 'A%'"

Parameter des Aufrufs

Einige Parameter haben Sie nun schon kennen gelernt, dennoch hier die Übersicht aller möglichen Parameter:

  • ObjectType: Konstante für den Objekttyp, hier sinnvollerweise acExportTable oder acExportQuery. Andere Werte wie acExportForm oder acExportReport erscheinen auf den ersten Blick sinnlos, aber haben doch ihre Daseinsberechtigung: Sie exportieren damit nämlich nicht etwa eine Formular- oder Berichtsdefinition, sondern die darin angezeigten Daten.
  • DataSource: Name der Datenquelle, also etwa der Tabelle oder der Abfrage.
  • DataTarget: Pfad zur Zieldatei für den Export. Vorhandene Dateien werden ohne Warnung überschrieben.
  • SchemaTarget: Ziel für die erstellte Schema-Datei.
  • PresentationTarget: Ziel für eine Datei mit Informationen zur Präsentation der Daten.
  • ImageTarget: Pfad für eventuell zu exportierende Bilder. Im Test konnten wir damit keine Bilder exportieren.
  • Encoding: Konstante für die Kodierung des XML-Dokuments (acUTF16 oder acUTF32)
  • OtherFlags: Kombination aus keinem, einem oder mehreren der folgenden Konstanten (hier nur die wichtigsten – mehr in der Onlinehilfe): acEmbedSchema (1) – sorgt dafür, dass Schemainformationen in das XML-Dokument geschrieben werden, acExcludePrimaryKeyAndIndexes (2) – schließt Primärschlüssel und Indizes beim Export aus, acExportAllTableAndFieldProperties (32) – exportiert Eigenschaften von Tabellen und Feldern mit dem Schema.
  • WhereCondition: Bedingung für die auszugebenden Datensätze
  • AdditionalData: Angabe weiterer Tabellen, die exportiert werden sollen. Ermöglicht die Auswahl der Tabellen, wie es beim Assistenten per TreeView möglich ist (s. Bild 4). AdditionalData bietet allerdings noch mehr Möglichkeiten.
  • Auswahl der zu exportierenden Tabellen per TreeView und Kontrollkästchen

    Bild 4: Auswahl der zu exportierenden Tabellen per TreeView und Kontrollkästchen

Daten aus mehreren Tabellen

Den Parameter AdditionalData schauen wir uns als Nächstes an. Onlinehilfe und Objektkatalog schweigen sich ebenso wie Intellisense über den Datentyp des zu übergebenden Wertes oder Objekts aus – hier taucht lediglich der Datentyp Variant auf, der ja verschiedene Typen aufnehmen kann. Schließlich hilft eine Suche nach dem Schlüsselwort AdditionalData im Objektkatalog weiter (s. Bild 5). Hier erfahren wir, dass es sich um eine eigene Klasse handelt, der wir wohl auch noch rekursiv weitere AdditionalData-Elemente zuweisen können. Das macht natürlich Sinn, denn auch der Assistent für den XML-Export bietet ja die verknüpften Tabellen in hierarchischer Anordnung an.

Der Objektkatalog liefert Informationen über den Datentyp von AdditionalData.

Bild 5: Der Objektkatalog liefert Informationen über den Datentyp von AdditionalData.

Export von Tabellen mit verknüpfter Lookuptabelle

Schauen wir uns ein einfaches Beispiel an – Kunden und ihre Anreden. Dazu wollen wir die Tabelle tblKunden exportieren und die Daten der Tabelle tblAnreden als zusätzliche Daten mitliefern. Wenn wir das mit dem Assistenten erledigen, definieren wir den Export wie in Bild 6. Das Ergebnis sieht dann so aus:

Definition des Exports von Kunden und ihren Anreden

Bild 6: Definition des Exports von Kunden und ihren Anreden

<?xml version="1.0" encoding="UTF-8"?>
<dataroot ...>
   <tblKunden>
     <KundeID>1</KundeID>
     <KundenCode>ALFKI</KundenCode>
     <Firma>Alfreds Futterkiste</Firma>
     <AnredeID>2</AnredeID>
     <Vorname>Maria</Vorname>
     <Nachname>Anders</Nachname>
     ...
   </tblKunden>
   ...
   <tblAnreden>
     <AnredeID>1</AnredeID>
     <Anrede>Herr</Anrede>
   </tblAnreden>
   <tblAnreden>
     <AnredeID>2</AnredeID>
     <Anrede>Frau</Anrede>
   </tblAnreden>
</dataroot>

Das heißt, dass die Anrede im tblKunden-Element als Fremdschlüsselwert gespeichert wird und alle Datensätze der Tabelle tblAnreden ebenfalls angehängt werden, sodass diese einfach wieder importiert werden können.

Nun schauen wir uns an, was geschieht, wenn wir den Export per VBA durchführen und dem Parameter AdditionalData ein Objekt des gleichnamigen Typs übergeben, das wir zuvor mit dem Element tblAnreden gefüllt haben.

Den Code finden Sie in Listing 1. Hier deklarieren wir das AdditionalData-Objekt mit der Variablen objAdditionalData und erstellen es dann mit der Methode CreateAdditionalData des Application-Objekts. Dann fügen wir mit der Add-Methode die Tabelle tblAnreden hinzu. Schließlich übergeben wir das Objekt mit dem Parameter AdditionalData an die Methode ExportXML.

Public Sub ExportKundenUndAnreden()
     Dim objAdditionalData As AdditionalData
     Set objAdditionalData = Application.CreateAdditionalData
     objAdditionalData.Add "tblAnreden"
     Application.ExportXML acExportTable, "tblKunden", _
         CurrentProject.Path & "KundenUndAnreden.xml", _
         AdditionalData:=objAdditionalData
End Sub

Listing 1: Export der Kundendaten und der Anreden

Das Ergebnis des Exports sieht diesmal wie folgt aus:

<?xml version="1.0" encoding="UTF-8"?>
<dataroot ...>
   <tblKunden>
     <KundeID>1</KundeID>
     <KundenCode>ALFKI</KundenCode>
     <Firma>Alfreds Futterkiste</Firma>
     <AnredeID>2</AnredeID>
     <Vorname>Maria</Vorname>
     <Nachname>Anders</Nachname>
     ...
     <tblAnreden>
       <AnredeID>2</AnredeID>
       <Anrede>Frau</Anrede>
     </tblAnreden>
   </tblKunden>
   ...
   <tblKunden>
     <KundeID>3</KundeID>
     <KundenCode>ANTON</KundenCode>
     <Firma>Antonio Moreno Taquería</Firma>
     <AnredeID>1</AnredeID>
     <Vorname>Antonio</Vorname>
     <Nachname>Moreno</Nachname>
     ...
     <tblAnreden>
       <AnredeID>1</AnredeID>
       <Anrede>Herr</Anrede>
     </tblAnreden>
   </tblKunden>
   ...
</dataroot>

Hier hängen die beiden möglichen Datensätze der Tabelle tblAnreden also nicht hinten am XML-Dokument an, sondern es wird jeweils der zutreffende Datensatz als Element dem aktuellen tblKunden-Element untergeordnet. Auch wenn der Import in eine Datenbank mit gleicher Datenstruktur nun nicht mehr so einfach möglich ist, so gibt es dennoch sicher Anwendungsfälle, in denen gerade die hier produzierte Variante nützlich ist.

Das bekommen Sie mit dem Assistenten so nicht hin. Aber können wir die vom Assistenten gelieferte Version, die ja die Daten beider Tabellen hintereinander ausgibt, per VBA nachbilden?

Export ohne Beziehung

Dies scheint nur zu funktionieren, wenn wir zwei Tabellen verwenden, die nicht über ein Fremdschlüsselfeld miteinander verknüpft sind. Da wir nun kaum die Beziehungen aus der Datenbank löschen wollen und auch nicht darauf aus sind, die relevanten Tabellen unter anderem Namen und ohne Beziehung zu duplizieren, verwenden wir einfach entsprechende Abfragen.

Erstellen Sie also eine Abfrage namens tblKunden_NoRelation, welche die Tabelle tblKunden als Datenquelle verwendet und alle Felder dieser Tabelle enthält. Das Gleiche erledigen Sie für die Tabelle tblAnreden. Hier nennen Sie die resultierende Abfrage tblAnreden_NoRelation. Beide zusammen sehen dann wie in Bild 7 aus.

Abfragen, um nicht verknüpfte Tabellen zu simulieren

Bild 7: Abfragen, um nicht verknüpfte Tabellen zu simulieren

Die Prozedur zum Exportieren brauchen wir nur an drei Stellen umzuformulieren: Wir fügen dem Objekt objAdditionalData die Abfrage tblAnreden_NoRelation hinzu, geben als Quelle der ExportXML-Methode die Abfrage tblKunden_NoRelation an und – ganz wichtig – legen als Wert für den Parameter Objekttyp statt acExportTable den Wert acExportQuery fest.

Sonst gibt es nämlich den Fehler mit der Nummer 2467 (»In dem von Ihnen eingegebenen Ausdruck wird auf ein Objekt verwiesen, das geschlossen oder nicht vorhanden ist.«). Die neue Version der Prozedur finden Sie in Listing 2.

Public Sub ExportKundenUndAnreden_NoRelation()
    Dim objAdditionalData As AdditionalData
    Set objAdditionalData = Application.CreateAdditionalData
    objAdditionalData.Add "tblAnreden_NoRelation"
    Application.ExportXML acExportQuery, "tblKunden_NoRelation", _
        CurrentProject.Path & "KundenUndAnreden.xml", _
        AdditionalData:=objAdditionalData
End Sub

Listing 2: Export der Kundendaten und der Anreden ohne Beziehung zwischen den Daten

Das Ergebnis sieht nun wie gewünscht aus – die Datensätze der Tabelle tblAnreden werden hinter den Kundendatensätzen eingefügt, statt mittendrin:

<?xml version="1.0" encoding="UTF-8"?>
<dataroot ...>
   <tblKunden_NoRelation>
     <KundeID>1</KundeID>
     <KundenCode>ALFKI</KundenCode>
     <Firma>Alfreds Futterkiste</Firma>
     <AnredeID>2</AnredeID>
     <Vorname>Maria</Vorname>
     <Nachname>Anders</Nachname>
     <Position>Vertriebsmitarbeiterin</Position>
     <PLZ>12209</PLZ>
     <Strasse>Obere Str. 57</Strasse>
     <Ort>Berlin</Ort>
     <Land>Deutschland</Land>
     <Telefon>030-0074321</Telefon>
     <Telefax>030-0076545</Telefax>
   </tblKunden_NoRelation>
   ...
   <tblAnreden_NoRelation>
     <AnredeID>1</AnredeID>
     <Anrede>Herr</Anrede>
   </tblAnreden_NoRelation>
   <tblAnreden_NoRelation>
     <AnredeID>2</AnredeID>
     <Anrede>Frau</Anrede>
   </tblAnreden_NoRelation>
</dataroot>

Export von 1:n-Daten

Beim Export einer Tabelle wie tblKunden und seiner Lookuptabelle tblAnreden geben wir die Tabelle mit dem Fremdschlüsselfeld der Beziehung als Parameter der ExportXML-Methode an und fügen die Tabelle mit dem an der Beziehung beteiligten Primärschlüsselfeld mit dem Parameter AdditionalData hinzu. Damit erhalten wir, wie wir oben gesehen haben, standardmäßig keine Verschachtelung der Daten, sondern diese werden nacheinander in das XML-Dokument geschrieben.

Wie sieht es aber aus, wenn wir die Tabellen der Beziehung in umgekehrter Reihenfolge angeben, also die Tabelle mit dem an der Beziehung beteiligten Primärschlüsselfeld als Parameter der ExportXML-Methode angeben und die Tabelle mit dem Fremdschlüsselfeld per AdditionalData-Parameter? Wir schauen uns dies am Beispiel der Tabellen tblKategorien und tblArtikel an. Im Assistenten würden wir dies wie in Bild 8 definieren.

Export von Kategorien und den verknüpften Artikeln per Assistent

Bild 8: Export von Kategorien und den verknüpften Artikeln per Assistent

Der Export würde in diesem Fall so aussehen:

<?xml version="1.0" encoding="UTF-8"?>
<dataroot ...>
   <tblKategorien>
     <KategorieID>1</KategorieID>
     <Kategoriename>Getränke</Kategoriename>
     <Beschreibung>Alkoholfreie Getränke...</Beschreibung>
     <Abbildung>...</Abbildung>
     <tblArtikel>
       <ArtikelID>1</ArtikelID>
       <Artikelname>Chai</Artikelname>
       <LieferantID>1</LieferantID>
       <KategorieID>1</KategorieID>
       <Liefereinheit>10 Kartons x 20 Beutel</Liefereinheit>
       <Einzelpreis>9</Einzelpreis>
       <Lagerbestand>39</Lagerbestand>
       <BestellteEinheiten>0</BestellteEinheiten>
       <Mindestbestand>10</Mindestbestand>
       <Auslaufartikel>0</Auslaufartikel>
     </tblArtikel>
     <tblArtikel>
       <ArtikelID>2</ArtikelID>
       <Artikelname>Chang</Artikelname>
       <LieferantID>1</LieferantID>
       <KategorieID>1</KategorieID>
       <Liefereinheit>24 x 12-oz-Flaschen</Liefereinheit>
       <Einzelpreis>9.5</Einzelpreis>
       <Lagerbestand>17</Lagerbestand>
       <BestellteEinheiten>40</BestellteEinheiten>
       <Mindestbestand>25</Mindestbestand>
       <Auslaufartikel>0</Auslaufartikel>
     </tblArtikel>
     ...
   </tblKategorien>
...
</dataroot>

Die Artikel einer Kategorie werden also dem jeweiligen tblKategorie-Element untergeordnet.

Unter VBA würden Sie den Export wie in Listing 3 realisieren. Das Ergebnis ist das Gleiche wie im zuvor beschriebenen Export über den Assistenten – hier verhalten sich der Export-Assistent und die ExportXML-Methode also identisch.

Public Sub ExportKategorienUndArtikel()
     Dim objAdditionalData As AdditionalData
     Set objAdditionalData = Application.CreateAdditionalData
     objAdditionalData.Add "tblArtikel"
     Application.ExportXML acExportTable, "tblKategorien", _
         CurrentProject.Path & "KategorienUndArtikel.xml", _
         AdditionalData:=objAdditionalData
End Sub

Listing 3: Export der Kategorien und der dazu gehörenden Artikel

Tiefer in die Hierarchie gehen

Nun wissen Sie, wie zusätzlich zu der zu exportierenden Tabelle noch eine weitere, verknüpfte Tabelle zum Export hinzufügen können und wie Sie diese direkt in die Elemente der Haupttabelle integrieren oder auch nicht. Was aber, wenn Sie nicht nur die Daten von Tabellen exportieren wollen, die direkt mit der Haupttabelle verknüpft sind, sondern noch darüber hinaus? Dazu wollen wir beispielsweise die Bestellungen inklusive Bestelldetails, Artikelinformationen, Kundendaten und Anreden exportieren. Für den Beginn reichen uns die drei Tabellen tblBestellungen, tblBestelldetails und tblArtikel aus. Wir geben einfach die Tabelle tblBestellungen als Datenquelle für Export­XML an und fügen die beiden Tabellen tblBestelldetails und tblArtikel über die Add-Methode dem AdditionalData-Objekt hinzu, das wir dann ebenfalls als Parameter an ExportXML übergeben (s. Listing 4). Das Ergebnis sieht nun wie folgt aus:

Public Sub ExportBestellungenBestelldetailsArtikel_I()
     Dim objAdditionalData As AdditionalData
     Set objAdditionalData = Application.CreateAdditionalData
     objAdditionalData.Add "tblBestelldetails"
     objAdditionalData.Add "tblArtikel"
     Application.ExportXML acExportTable, "tblBestellungen", _
         CurrentProject.Path & "Bestellungen.xml", _
         AdditionalData:=objAdditionalData
End Sub

Listing 4: Export der Bestellungen samt Bestelldetails und Artikeldetails

<?xml version="1.0" encoding="UTF-8"?>
<dataroot ...>
   <tblBestellungen>
     <BestellungID>10248</BestellungID>
     <KundeID>90</KundeID>
     <PersonalID>5</PersonalID>
     <Bestelldatum>2011-07-26T00:00:00</Bestelldatum>
     <Lieferdatum>2011-08-23T00:00:00</Lieferdatum>
     ...
     <tblBestelldetails>
       <BestelldetailID>1</BestelldetailID>
       <BestellungID>10248</BestellungID>
       <ArtikelID>11</ArtikelID>
       <Einzelpreis>7</Einzelpreis>
       <Anzahl>12</Anzahl>
       <Rabatt>0</Rabatt>
     </tblBestelldetails>
     <tblBestelldetails>
       ...
     </tblBestelldetails>
     <tblBestelldetails>
       ...
     </tblBestelldetails>
   </tblBestellungen>
   ...
   <tblArtikel>
     <ArtikelID>1</ArtikelID>
     <Artikelname>Chai</Artikelname>
     ...
   </tblArtikel>
   ...
</dataroot>

Hier werden also die Datensätze der Tabelle tblBestelldetails unterhalb denen der Tabelle tblBestellungen im XML-Dokument angeordnet. Die Datensätze der Tabelle tblArtikel folgen im Anschluss an die tblBestellungen-Elemente.

Bestellungen, Bestelldetails und Artikeldetails verschachteln

Nun wollen wir aber, dass die Artikeldetails aus der Tabelle tblArtikel immer direkt unter den Bestelldetails angeordnet werden, die sich auf den jeweiligen Artikel beziehen – also etwa wie hier:

<?xml version="1.0" encoding="UTF-8"?>
<dataroot ...>
   <tblBestellungen>
     <BestellungID>10248</BestellungID>
     <KundeID>90</KundeID>
     <PersonalID>5</PersonalID>
     <Bestelldatum>2011-07-26T00:00:00</Bestelldatum>
     ...
     <tblBestelldetails>
       <BestelldetailID>1</BestelldetailID>
       <BestellungID>10248</BestellungID>
       <ArtikelID>11</ArtikelID>
       <Einzelpreis>7</Einzelpreis>
       <Anzahl>12</Anzahl>
       <Rabatt>0</Rabatt>
       <tblArtikel>
         <ArtikelID>11</ArtikelID>
         <Artikelname>Queso Cabrales</Artikelname>
         ...
       </tblArtikel>
     </tblBestelldetails>
     <tblBestelldetails>
       <BestelldetailID>2</BestelldetailID>
       <BestellungID>10248</BestellungID>
       <ArtikelID>42</ArtikelID>
       <Einzelpreis>4.9</Einzelpreis>
       <Anzahl>10</Anzahl>
       <Rabatt>0</Rabatt>
       <tblArtikel>
         <ArtikelID>42</ArtikelID>
         <Artikelname>Singaporean Hokkien</Artikelname>
         ...
       </tblArtikel>
     </tblBestelldetails>
     ...
   </tblBestellungen>
</dataroot>

Diese Konstellation können Sie mit dem XML-Export-Assistenten nicht bewerkstelligen, aber mit VBA. Die dazu benötigte Prozedur finden Sie in Listing 5. Der Clou hierbei ist, dass wir die Tabelle tblArtikel nicht einfach als weiteres Element des AdditionalData-Objekts angeben, sondern dieses dem zuerst hinzugefügten Element auf Basis der Tabelle tblBestelldetails hinzufügen. Dabei referenzieren wir das bereits angelegte Element mit obj­AdditionalData.Item("tblBestelldetails") und fügen mit dessen Add-Methode die Tabelle tblArtikel als untergeordnetes Element hinzu. Auf diese Weise erhalten wir die zuvor beschriebene Anordnung, bei welcher die Artikeldetails noch den Bestelldetails untergeordnet werden.

Public Sub ExportBestellungenBestelldetailsArtikel_II()
     Dim objAdditionalData As AdditionalData
     Set objAdditionalData = Application.CreateAdditionalData
     objAdditionalData.Add "tblBestelldetails"
     objAdditionalData.Item("tblBestelldetails").Add "tblArtikel"
     Application.ExportXML acExportTable, "tblBestellungen", _
         CurrentProject.Path & "Bestellungen.xml", _
         AdditionalData:=objAdditionalData
End Sub

Listing 5: Export der Bestellungen samt Bestelldetails und Artikeldetails, diesmal weiter verschachtelt

Dies ergibt zwar redundante Daten im XML-Dokument, aber es gibt sicher Anwendungsfälle, bei denen Sie die Daten wie hier dargestellt besser verarbeiten können als wenn etwa die Artikeldetails in einfacher Form hinten an das XML-Dokument angehängt werden.

Transformation mit .xslt-Datei

Im Beitrag XML-Export ohne VBA (www.access-im-unternehmen.de/1045) haben Sie erfahren, wie Sie unter Angabe einer .xslt-Datei eine Transformation der exportierten Daten durchführen können.

So ist es beispielsweise möglich, nur bestimmte Felder im XML-Dokument zu erhalten, Daten statt als Inhalt eines Elements als Attribut anzugeben oder auch die komplette Struktur zu verändern.

Dort haben Sie die .xslt-Datei nach einem Klick auf die Schaltfläche Transformieren... der erweiterten Optionen des Export-Assistenten angegeben. Die Methode Export­XML bietet leider keine solche Option.

Sie müssen die Transformation also nach der Erstellung der Export-XML-Datei selbst durchführen, was mit einigen VBA-Anweisungen jedoch leicht zu erledigen ist.

Wie dies gelingt, beschreiben wir im Detail im Beitrag XML-Dokumente transformieren mit XSLT (www.access-im-unternehmen.de/1047). In Listing 6 finden Sie nur die Kurzfassung, bei der wir die im Beitrag XML-Export ohne VBA vorgestellte .xslt-Datei auf ein Export-Ergebnis anwenden.

Public Sub ExportUndXSLT()
     Dim objAdditionalData As AdditionalData
     Dim objUntransformiert As MSXML2.DOMDocument
     Dim objXSLT As MSXML2.DOMDocument
     Dim objTransformiert As MSXML2.DOMDocument
     Set objAdditionalData = Application.CreateAdditionalData
     objAdditionalData.Add "tblArtikel"
     Application.ExportXML acExportTable, "tblKategorien", _
         CurrentProject.Path & "KategorienUndArtikel_Untransformiert.xml", _
         AdditionalData:=objAdditionalData
     Set objUntransformiert = New MSXML2.DOMDocument
     objUntransformiert.Load CurrentProject.Path & "KategorienUndArtikel_Untransformiert.xml"
     Set objXSLT = New MSXML2.DOMDocument
     objXSLT.Load CurrentProject.Path & "KategorienUndArtikel.xslt"
     Set objTransformiert = New MSXML2.DOMDocument
     objUntransformiert.transformNodeToObject objXSLT, objTransformiert
     objTransformiert.Save CurrentProject.Path & "KategorienUndArtikel_Transformiert.xml"
End Sub

Listing 6: Transformieren einer frisch exportierten XML-Datei

Hier erstellen wir drei XML-DOMDocument-Objekte. Das erste nimmt die erstellte XML-Datei auf, das zweite die .xslt-Datei. Für das zu transformierende DOMDocument-Objekt rufen wir die Methode transformNodeToObject auf und übergeben dieser als ersten Parameter den Verweis auf die .xslt-Datei und als zweiten den Verweis auf das zu erstellende transformierte XML-Dokument.

Bitte geben Sie die Zeichenfolge in das nachfolgende Textfeld ein

Die mit einem * markierten Felder sind Pflichtfelder.

Ich habe die Datenschutzbestimmungen zur Kenntnis genommen.