XML-Code-Builder

Ein XML-Code-Builder – was soll das denn sein Nun: Stellen Sie sich einfach vor, Ihr Kunde liefert Ihnen eine Datenbank und ein XML-Dokument und möchte, dass Sie ihm den Code liefern, mit dem er ein so aufgebautes XML-Dokument mit Daten aus der Datenbank füllen kann. Kein Problem, sagen Sie – es ist zwar etwas Fleißarbeit, aber das bekommen Sie schon hin. Ach: Ist Fleißarbeit nicht das erklärte Feindbild eines Access-Entwicklers Genau! Und deshalb liefert dieser Beitrag Ihnen die Werkzeuge, um das Grundgerüst des zu erstellenden Codes aufzubauen.

Mir ist das schon einige Male untergekommen: Ein Kunde möchte Daten aus seiner Datenbank in das XML-Format übertragen, weil dies die einzige Möglichkeit ist, die Daten an eine weitere Anwendung, einen Webservice und so weiter zu übergeben. Bereits nach dem Zusammenstellen der ersten paar Zeilen Code war klar: Das lässt sich automatisieren, zumindest für das Grundgerüst. Dass da noch ein wenig Handarbeit nötig ist, war klar, aber zumindest das Kopieren und Einfügen bestehender Codesegmente und das Anpassen an die jeweils zu schreibenden XML-Elemente auf Basis der Tabellenfelder ist erstens zu mühsam und zweitens zu fehleranfällig.

Also toben wir uns lieber an ein paar schicken VBA-Routinen aus, die uns den Großteil der Arbeit abnehmen. Was ist das Ziel der Lösung, die wir in diesem Beitrag vorstellen Stellen Sie sich vor, Sie sollten aus der Südsturm-Datenbank heraus einen Export fahren, der etwa in einen Onlineshop importiert werden soll. Das XML-Dokument zum Übertragen der Artikeldaten zum Onlineshop soll dann beispielsweise so aussehen, wie ein Beispieldokument verrät:

<xml version="1.0">
<Katalog>
    <Datum>11.07.2011</Datum>
    <Zeit>12:29:49</Zeit>
    <Artikelliste>
        <Artikel ID="1">
            <Artikelname>Artikel 1</Artikelname>
            <Waehrung>EUR</Waehrung>
            <Einzelpreis>10,00</Einzelpreis>
        </Artikel>
        <Artikel ID="2">
            <Artikelname>Artikel 2</Artikelname>
            <Waehrung>EUR</Waehrung>
            <Einzelpreis>20,00</Einzelpreis>
        </Artikel>
        ...
    </Artikelliste>
</Katalog>

Sie müssen nun Code schreiben, der erstens die Basiselemente wie die XML-Auszeichnung und die Elemente Katalog, Datum, Zeit und Artikelliste erzeugt. Danach folgt eine Schleife über alle Einträge der Tabelle tblArtikel, in der für jeden Artikel ein Artikel-Element sowie die darunter befindlichen Elemente angelegt werden.

Im Detail würde bereits zum Erstellen dieses einfachen XML-Dokuments die Prozedur aus Listing 1 nötig sein. Die Prozedur erstellt zunächst die Kopfdaten, danach folgen die Elemente Katalog und Artikelliste sowie in einer Do While-Schleife über alle Artikel die Elemente Artikel (mit dem Attribut ID), Artikelname, Waehrung und Einzelpreis. Um die Struktur abzubilden, legt die Prozedur jeweils die übergeordneten Elemente an, speichert einen Verweis auf diese Elemente in einer entsprechenden Objektvariablen und verwendet diese dann, um weitere Elemente unterzuordnen. Das bedeutet, dass Sie prinzipiell für jeden Elementtyp eine Objektvariable erzeugen müssen, in deren Kontext dann die untergeordneten Elemente erstellt werden können.

Listing 1: Zusammenstellen eines XML-Dokuments mit Artikeldaten

Public Sub Katalog()
    Dim db As DAO.Database
    Dim rst As DAO.Recordset
    Dim objXML As MSXML2.DOMDocument
    Dim objPI As MSXML2.IXMLDOMProcessingInstruction
    Dim objKatalog As MSXML2.IXMLDOMElement
    Dim objDatum As MSXML2.IXMLDOMElement
    Dim objZeit As MSXML2.IXMLDOMElement
    Dim objArtikelliste As MSXML2.IXMLDOMElement
    Dim objArtikel As MSXML2.IXMLDOMElement
    Dim objArtikelname As MSXML2.IXMLDOMElement
    Dim objWaehrung As MSXML2.IXMLDOMElement
    Dim objEinzelpreis As MSXML2.IXMLDOMElement
    Set db = CurrentDb
    Set rst = db.OpenRecordset("SELECT * FROM tblArtikel", dbOpenDynaset)
    Set objXML = New MSXML2.DOMDocument
    Set objPI = objXML.createProcessingInstruction("xml", "version=""1.0"" encoding=""utf-8""")
    objXML.appendChild objPI
    Set objKatalog = objXML.createElement("Katalog")
    objXML.appendChild objKatalog
    Set objDatum = objXML.createElement("Datum")
    objKatalog.appendChild objDatum
    objDatum.Text = Date
    Set objZeit = objXML.createElement("Zeit")
    objKatalog.appendChild objZeit
    objZeit.Text = Time
    Set objArtikelliste = objXML.createElement("Artikelliste")
    objKatalog.appendChild objArtikelliste
    Do While Not rst.EOF
         Set objArtikel = objXML.createElement("Artikel")
        objArtikelliste.appendChild objArtikel
        objArtikel.setAttribute "ID", rst!ArtikelID
        Set objArtikelname = objXML.createElement("Artikelname")
        objArtikel.appendChild objArtikelname
        objArtikelname.Text = rst!Artikelname
        Set objWaehrung = objXML.createElement("Waehrung")
        objArtikel.appendChild objWaehrung
        objWaehrung.Text = "EUR"
        Set objEinzelpreis = objXML.createElement("Einzelpreis")
        objArtikel.appendChild objEinzelpreis
        objEinzelpreis.Text = rst!Einzelpreis
        rst.MoveNext
    Loop
    Debug.Print FormatXML(objXML.XML)
End Sub

Verweis auf die XML-Bibliothek

Damit Sie die notwendigen Routinen zum Erstellen und Auslesen der XML-Dokumente unter Zuhilfenahme von IntelliSense erstellen können, brauchen Sie einen Verweis auf die Bibliothek Microsoft XML, vx.0. Diesen fügen Sie über den Verweise-Dialog hinzu, den Sie mit dem Menüeintrag Extras|Verweise öffnen.

Vereinfachung der Code-Erstellung

Der erste Schritt auf dem Weg zu einer massiven Vereinfachung der Erstellung von Code zum Produzieren von XML-Dokumenten sind Routinen, welche die immer wiederkehrenden Befehle kapseln.

Verarbeitungsanweisung hinzufügen

Ein XML-Dokument enthält in der Regel die folgende Zeile:

<xml version="1.0">

Um diese Zeile zu einem jungfräulichen XML-Dokument hinzuzufügen, das mit einer entsprechenden DOMDocument-Variablen referenziert wird, verwenden Sie die Prozedur aus Listing 2. Die Prozedur fügt der mit dem als Parameter übergebenen XML-Dokument die gewünschte Zeile hinzu. Um ein Dokument nur mit der Verarbeitungsanweisung auszustatten, benötigen Sie nun nur noch die folgende kleine Prozedur:

Listing 2: Erstellen der Verarbeitungsanweisung eines XML-Dokuments

Public Sub AddPI(objXML As MSXML2.DOMDocument)
    Dim objPI As MSXML2.IXMLDOMProcessingInstruction
    Set objPI = objXML.createProcessingInstruction("xml", "version=""1.0"" encoding=""utf-8""")
    objXML.appendChild objPI
End Sub
Public Sub DokumentMitPI()
    Dim objXML As MSXML2.DOMDocument
    Set objXML = New MSXML2.DOMDocument
    AddPI objXML
    Debug.Print objXML.XML
End Sub

Diese Prozedur erstellt das XML-Dokument, fügt die Verarbeitungsanweisung hinzu und gibt das Dokument im Direktfenster aus.

Elemente hinzufügen

Nun folgen die eigentlichen Elemente des XML-Dokuments. Zum Hinzufügen eines einfachen Elements benötigen Sie eigentlich die folgenden beiden Anweisungen:

Set objKatalog = objXML.createElement("Katalog")
objXML.appendChild objKatalog

Damit fügen Sie ein Element mit dem Namen Katalog als Root-Element hinzu, das jedoch noch keinen Inhalt besitzt:

<xml version="1.0">
<Katalog/>

Um diesem Element das Element Artikelliste unterzuordnen, legen Sie das Element im Kontext von objXML an, hängen es aber mit appendChild an das Element objKatalog an:

Set objArtikelliste = objXML.
createElement("Artikelliste")
objKatalog.appendChild objArtikelliste

Das Result sieht dann so aus:

<xml version="1.0">
<Katalog><Artikelliste/></Katalog>

Das Anhängen der Artikel-Elemente geschieht genau so, beim Element Artikelname kommt jedoch noch ein Inhalt hinzu – genau genommen ein Text:

Set objArtikelname = objXML. createElement("Artikelname")
objArtikel.appendChild objArtikelname
objArtikelname.Text = rst!Artikelname

Dazu speichern Sie wiederum den Verweis auf das Element und verwenden dann dessen Text-Eigenschaft, um den Inhalt hinzuzufügen. Wie wäre es, diese Objekte – egal, ob mit oder ohne Text – sämtlich mit Einzeilern anzulegen Schauen Sie sich einmal die Prozedur aus Listing 3 an. Diese erwartet drei Parameter:

Listing 3: Erstellung der Elemente des XML-Dokuments

Public Function CreateSubElement(objElement As Object, strElementname As String, Optional strText As String) As MSXML2.IXMLDOMElement
    Dim strTypename As String
    Dim objDocument As MSXML2.DOMDocument
    Dim objXMLElement As MSXML2.IXMLDOMElement
    strTypename = TypeName(objElement)
    Select Case strTypename
        Case "DOMDocument"
            Set objXMLElement = objElement.createElement(strElementname)
            objElement.appendChild objXMLElement
        Case "IXMLDOMElement"
            Set objDocument = objElement.ownerDocument
            Set objXMLElement = objDocument.createElement(strElementname)
            objElement.appendChild objXMLElement
    End Select
    If Len(strText) > 0 Then
        objXMLElement.Text = strText
    End If
    Set CreateSubElement = objXMLElement
End Function
  • objElement: Verweis auf das Element, unterhalb dessen das neue Element angelegt werden soll
  • strElementname: Name des neuen Elements, also beispielsweise Katalog, Artikelliste oder Artikel
  • strText: Text, den das Element enthalten soll, also beispielsweise Artikelname, Währung oder Einzelpreis

Sie können als objElement sowohl das Dokument selbst übergeben als auch ein bestehendes Element. Um dem mit objXML referenzierten Dokument die ersten vier Elemente Katalog, Artikelliste, Artikel und Artikelname samt Inhalt hinzuzufügen, benötigen Sie mit dieser Funktion nur noch vier Anweisungen (und zusätzlich die Variablen-Deklarationen):

Set objKatalog = CreateSubElement(objXML, "Katalog")
Set objArtikelliste = CreateSubElement(objKatalog, "Artikelliste")
Set objArtikel = CreateSubElement(objArtikelliste, "Artikel")
Set objArtikelname = CreateSubElement(objArtikel, "Artikelname", "Artikelname erster Artikel")

Die Prozedur prüft einfach den Typ des mit objElement übergebenen Objekts (entweder DOMDocument oder IXMLDOMElement) und ordnet das neue Element entsprechend unter. Sollte der Benutzer den optionalen Parameter strText angegeben haben, wird dem soeben erzeugten Objekt auch noch der Text hinzugefügt. Den größten Teil des Dokuments können Sie allein mit den beiden Funktionen AddPi und CreateSubElement erstellen.

Attribut hinzufügen

Das Hinzufügen eines Attributs zu einem Element benötigt nur eine einzige Zeile. Im folgenden Beispiel soll dem Element objArtikel ein Attribut namens ID mit dem Wert des Feldes ArtikelID der Datensatzgruppe rst hinzugefügt werden:

objArtikel.setAttribute "ID", rst!ArtikelID

Auch wenn dies keine Vereinfachung bringt, haben wir auch für das Hinzufügen eines Attributs eine eigene Prozedur bereitgestellt. Sie finden diese in Listing 4.

Listing 4: Hinzufügen eines Attributs zu einem Element

Public Sub CreateAttribute(objElement As MSXML2.IXMLDOMElement, strAttributename As String, _
        strAttributeValue As String)
    objElement.setAttribute strAttributename, strAttributeValue
End Sub

Zwischenfazit

Statt der ursprünglichen Prozedur erhalten Sie nun ein wesentlich handlicheres Gebilde, das wie in Listing 5 aussieht. Dadurch, dass die Werte direkt zugewiesen werden können, müssen Sie hier außerdem viel weniger Variablen zum Speichern der Verweise auf die XML-Elemente hinzufügen.

Listing 5: Erstellen des XML-Dokuments mit Hilfsfunktionen

Public Sub Katalog_()
    Dim db As DAO.Database
    Dim rst As DAO.Recordset
    Dim objXML As MSXML2.DOMDocument
    Dim objRoot As MSXML2.IXMLDOMElement
    Dim objArtikelliste As MSXML2.IXMLDOMElement
    Dim objArtikel As MSXML2.IXMLDOMElement
    Set db = CurrentDb
    Set rst = db.OpenRecordset("SELECT * FROM tblArtikel", dbOpenDynaset)
    Set objXML = New MSXML2.DOMDocument
    AddPI objXML
    Set objRoot = CreateSubElement(objXML, "Katalog")
    CreateSubElement objRoot, "Datum", "11.07.2011"
    CreateSubElement objRoot, "Zeit", "12:29:49"
    Set objArtikelliste = CreateSubElement(objRoot, "Artikelliste", "")
    Do While Not rst.EOF
         Set objArtikel = CreateSubElement(objArtikelliste, "Artikel", "")
        CreateAttribute objArtikel, "ID", "1"
        CreateSubElement objArtikel, "Artikelname", "Artikel 1"
        CreateSubElement objArtikel, "Waehrung", "EUR"
        CreateSubElement objArtikel, "Einzelpreis", "10,00"
        rst.MoveNext
    Loop
    Debug.Print FormatXML(objXML.XML)
End Sub

XML-Baukasten

Durch das geschickte Auslagern von wiederverwendbaren Code-Strukturen benötigen Sie nun wesentlich weniger Zeilen, um das gleiche Ziel zu erreichen. Wo aber bleibt nun die versprochene automatische Code-Erstellung Hier kommt sie – in Form des XMLBuilders.

Die Grundidee ist es, die Struktur des zu erstellenden XML-Dokuments auszulesen und darauf basierend den VBA-Code zu erzeugen, der zum Erstellen genau dieses XML-Dokuments nötig wäre.

Die nachfolgend vorgestellten Funktionen erstellen genau den Code, der zum Reproduzieren des Dokuments nötig ist. Allerdings werden sich wiederholende Elemente automatisch ausgeschlossen! Das zweite Artikel-Element des folgenden Beispiels wird also beispielsweise ignoriert. Lediglich neue Elemente oder Attribute, die bislang noch nicht vorkamen, werden berücksichtigt:

<xml version="1.0">
<Katalog>
    <Datum>11.07.2011</Datum>
    <Zeit>12:29:49</Zeit>
    <Artikelliste>
        <Artikel ID="1">
            <Artikelname>Artikel 1</Artikelname>
            <Waehrung>EUR</Waehrung>
            <Einzelpreis>10,00</Einzelpreis>
        </Artikel>
        <Artikel ID="2">
            <Artikelname>Artikel 2</Artikelname>
            <Waehrung>EUR</Waehrung>
            <Einzelpreis>20,00</Einzelpreis>
        </Artikel>
    </Artikelliste>
</Katalog>

XML-Dokument analysieren

Am einfachsten nutzen Sie die Funktionen des Moduls mdlXMLBuilder, wenn Sie das zu erstellende XML-Dokument als Vorlage verwenden, beispielsweise diese gekürzte Variante des vorherigen Beispiels:

<xml version="1.0">
<Katalog>
    <Datum>11.07.2011</Datum>
    <Zeit>12:29:49</Zeit>
    <Artikelliste>
        <Artikel ID="1">
            <Artikelname>Artikel 1</Artikelname>
            <Waehrung>EUR</Waehrung>
            <Einzelpreis>10,00</Einzelpreis>
        </Artikel>
    </Artikelliste>
</Katalog>

Speichern Sie das Dokument an geeigneter Stelle, am besten im Verzeichnis der Access-Datei mit dem Modul mdlXMLBuilder. Rufen Sie dann die Funktion XMLBuilder mit dem Dateinamen als Parameter auf und geben Sie das Ergebnis beispielsweise im Direktfenster aus (s. Bild 1):

pic001.png

Bild 1: Erstellen einer XMLBuilder-Prozedur im Direktfenster

XMLBuilder CurrentProject.Path & "\Katalog.xml"

Die Funktion gibt das Ergebnis im Direktfenster aus. Die resultierende Prozedur sieht so wie in Bild 1 aus.

Wenn Sie diese Prozedur aufrufen, erstellt sie genau das zuvor in der XML-Datei gespeicherte und als Vorlage dienende XML-Dokument. Nun, da Sie eine Prozedur haben, die Ihnen die Anweisungen zum Schreiben von XML-Dokumenten liefert, brauchen Sie das Ergebnis nur noch anzupassen. Sie müssten also beispielsweise den hier für das Attribut ID des Elements Artikel übergebenen Ausdruck parametrisieren. Die Zeile

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

den kompletten Artikel im PDF-Format mit Beispieldatenbank

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar