Wenn Sie ein Abonnement des Magazins 'Access im Unternehmen' besitzen, können Sie sich anmelden und den kompletten Artikel lesen.
Anderenfalls können Sie das Abonnement hier im Shop erwerben.
XML-Zugriff per XPath
XML-Dokumente erscheinen je nach Größe auf den ersten Blick oft unübersichtlich und mächtig. Wie soll man hier die gewünschten Daten extrahieren – und das auch noch programmgesteuert per VBA? Beispielsweise, um Informationen aus einem XML-Dokument in eine Access-Tabelle zu übertragen? Dafür steht die Abfragesprache XPath zur Verfügung. Sie erlaubt es, mit verschiedenen Ausdrucken gezielt auf Elemente mit bestimmten Namen oder Eigenschaften zuzugreifen. Dieser Beitrag zeigt anhand einiger Beispiele, wie Sie XPath unter Access/VBA einsetzen.
Voraussetzungen
Um die folgenden Beispiele auszuführen, benötigen Sie eine Beispieldatenbank mit einem Verweis auf die XML-Bibliothek von Microsoft. Dazu öffnen Sie den Verweise-Dialog (VBA-Editor, Menüeintrag Extras|Verweise) und wählen dort den Eintrag Microsoft XML, v3.0 aus (s. Bild 1). Mit Microsoft XML, v6.0 gab es bei der Erstellung der Beispiele Probleme, da hier einige Methoden nicht die erwarteten Ergebnisse lieferten.
Bild 1: Hinzufügen des Verweises auf die XML-Bibliothek
Beispieldokument
Um per VBA auf den Inhalt eines XML-Dokuments zugreifen zu können, benötigen Sie zunächst ein solches. Unseres heißt KategorienUndArtikel.xml und sollte sich im gleichen Verzeichnis wie die Beispieldatenbank befinden, da die Zugriffe auf diese Datei dahingehend ausgerichtet sind. Der Inhalt dieser XML-Datei sieht wie in Listing 1 aus.
<?xml version="1.0" encoding="UTF-16"?>
<Bestellverwaltung xmlns="http://www.w3.org/TR/REC-html40">
<Kategorie KategorieID="1">
<Kategoriename>Getränke</Kategoriename>
<Beschreibung>Alkoholfreie Getränke, Kaffee, Tee, Bier</Beschreibung>
<Artikel ArtikelID="1">
<Artikelname>Chai</Artikelname>
<Einzelpreis>EUR 9.00</Einzelpreis>
</Artikel>
<Artikel ArtikelID="2">
<Artikelname>Chang</Artikelname>
<Einzelpreis>EUR 9.50</Einzelpreis>
</Artikel>
..
</Kategorie>
<Kategorie KategorieID="2">
<Kategoriename>Gewürze</Kategoriename>
<Beschreibung>Süße und saure Soßen, Gewürze</Beschreibung>
<Artikel ArtikelID="3">
<Artikelname>Aniseed Syrup</Artikelname>
<Einzelpreis>EUR 5.00</Einzelpreis>
</Artikel>
<Artikel ArtikelID="4">
<Artikelname>Chef Anton's Cajun Seasoning</Artikelname>
<Einzelpreis>EUR 11.00</Einzelpreis>
</Artikel>
...
</Kategorie>
...
</Bestellverwaltung>
Listing 1: XML-Dokument für die Beispiele dieses Beitrags
Um per XPath per VBA auf ein XML-Dokument zugreifen zu können, müssen Sie dieses zunächst in den Speicher laden, beziehungsweise es mit einem geeigneten Objekt referenzieren. Dies erledigen Sie mit dem Code, wie er etwa in der folgenden Prozedur enthalten ist:
Public Sub DokumentLaden()
Dim strDatei As String
Dim objXML As MSXML2.DOMDocument
strDatei = CurrentProject.Path & "KategorienUndArtikel.xml"
Set objXML = New MSXML2.DOMDocument
objXML.Load strDatei
If Not Len(objXML.XML) = 0 Then
Debug.Print objXML.XML
Else
Debug.Print objXML.parseError.errorCode, objXML.parseError.reason
End If
End Sub
Die Prozedur erstellt ein neues Objekt des Typs DOMDocument und verwendet die Load-Methode, um die angegebene Datei in das Objekt zu laden. Gelingt dies, sollte die Länge der über die Eigenschaft XML zu ermittelnde Zeichenkette, also der Inhalt des Dokuments, größer als 0 sein. In diesem Fall soll die Prozedur den Inhalt des XML-Dokuments im Direktbereich des VBA-Editors ausgeben. Anderenfalls ist etwas beim Einlesen schiefgelaufen. Dann soll die Fehlernummer samt der Fehlerbeschreibung im Direktbereich erscheinen.
XPath per VBA nutzen
Um die Abfragesprache XPath von VBA aus nutzen zu können, gibt es zwei Funktionen. Die erste heißt selectSingleNode und erwartet einen XPath-Ausdruck als Parameter. Sie liefert ein einziges Node-Element als Ergebnis zurück, sofern die Abfrage ein Ergebnis hat.
Die zweite Funktion heißt selectNodes und liefert eine Auflistung des Typs DOMSelection zurück. Sie kann kein, ein oder mehrere Elemente enthalten, die wiederum den Typ DOMDocument für das Dokument-Objekt, IXMLDOMProcessingInstruction für das -Element oder IXMLDOMElement für die übrigen Elemente aufweisen.
Üblicherweise werden Sie aber mit den Elementen des Typs IXMLDOMElement arbeiten, ein Zugriff auf das DOMDocument-Objekt oder das IXMLDOMProcessingInstruction-Objekt ist selten in Zusammenhang mit dem Zugriff per XPath nötig.
Unsere Beispielprozedur für das Erstellen eines XML-Dokuments und das Füllen dieses Objekts aus einer XML-Datei haben wir etwas abgewandelt, damit wir damit mit einer Anweisung innerhalb unserer Beispielprozeduren auf das XML-Dokument zugreifen können (s. Listing 2).
Public Function GetDocument() As MSXML2.DOMDocument
Dim strDatei As String
Dim objXML As MSXML2.DOMDocument
strDatei = CurrentProject.Path & "KategorienUndArtikel.xml"
Set objXML = New MSXML2.DOMDocument
objXML.Load strDatei
If Not Len(objXML.XML) = 0 Then
Set GetDocument = objXML
Else
MsgBox "Fehler " & objXML.parseError.errorCode & ": " & objXML.parseError.reason
End If
End Function
Listing 2: Hilfsfunktion, um ein gefülltes DOMDocument-Element zu holen
Auf das Root-Element zugreifen
Ein Beispiel für den Zugriff auf ein einzelnes XML-Element sieht danach wie folgt aus:
Public Sub RootelementHolen()
Dim objElement As MSXML2.IXMLDOMElement
Dim objDocument As MSXML2.DOMDocument
Set objDocument = GetDocument
Set objElement = _
objDocument.selectSingleNode("Bestellverwaltung")
Debug.Print objElement.XML
End Sub
Dies liest das Element Bestellverwaltung samt allen untergeordneten Elementen ein. Wenn wir wie in obiger Beispielprozedur den Inhalt der XML-Eigenschaft im Direktbereich ausgeben, erhalten wir also fast das komplette Dokument – mit Ausnahme der Formatinformationen in der -Zeile.
Dies gelingt aber auch nur über den XPath-Ausdruck Bestellverwaltung, weil wir die selectSingleNode-Funktion für das DOMDocument-Objekt aufrufen und das Bestellverwaltung-Objekt diesem direkt untergeordnet ist.
Wir könnten also nicht etwa auf das erste Kategorie-Objekt zugreifen, indem wir einfach folgenden Ausdruck nutzen:
Set objElement = objDocument.selectSingleNode("Kategorie")
Wenn wir dies versuchen, erhalten wir eine Fehlermeldung wie in Bild 2. Die Anweisung Set objElement... löst zwar noch keinen Fehler aus. Aber objElement wird hier nicht gefüllt und der folgende Zugriff auf eine Eigenschaft von objElement führt dann zum Fehler.
Bild 2: Fehler beim Zugriff auf ein XML-ElementAuf ein direktes Unterelement des Root-Elements zugreifen
Mit dem Namen eines Elements allein können Sie also nur auf ein Element zugreifen, wenn sich dieses direkt unterhalb des Objekts befindet, für das Sie die SelectSingleNode-Methode aufrufen.
Dafür müssten Sie zuerst das Root-Element Bestellverwaltung per IXMLDomElement-Variable referenzieren und könnten dann von dort aus auf das Kategorie-Element zugreifen:
Dim objBestellverwaltung As MSXML2.IXMLDOMElement
Dim objKategorie As MSXML2.IXMLDOMElement
Dim objDocument As MSXML2.DOMDocument
Set objDocument = GetDocument
Set objBestellverwaltung = objDocument.selectSingleNode("Bestellverwaltung")
Set objKategorie = objBestellverwaltung. selectSingleNode("Kategorie")
Debug.Print objKategorie.XML
Dies gibt den Inhalt des ersten Kategorie-Elements aus.
An dieser Stelle ist es wichtig zu erwähnen, dass die SelectSingleNode immer das erste Element liefert, das dem angegebenen Ausdruck entspricht. Während es nur ein Bestellverwaltung-Element gibt, befinden sich darunter allerdings gleich sieben Kategorie-Elemente. Davon liefert SelectSingleNode dann das erste.
Auf mehrere Elemente zugreifen
Das ist ein guter Anlass, die Funktion selectNodes vorzustellen. Sie liefert nicht nur ein einziges Element zurück, sondern kann auch einmal kein oder mehrere Elemente zurückgeben. Diese kommen immer in einer Auflistung vom Typ DOMSelection.
Wenn Sie die gefundenen Elemente mit der For Each-Schleife durchlaufen wollen, definieren Sie wie im folgenden Beispiel sowohl ein Objekt namens objKategorie mit dem Typ IXMLDOMElement als Laufvariable sowie eines für die Auflistung namens objKategorien mit dem Typ IXMLDOMSelection.
Dann referenzieren Sie wieder das Root-Element und nutzen dann dessen selectNodes-Funktion, um alle untergeordneten Kategorie-Elemente zu ermitteln. Diese landen dann im Auflistungsobjekt objKategorien. Dieses können wir dann per For Each-Schleife mit der Laufvariablen objKategorie durchlaufen. Innerhalb der Schleife geben wir wieder den Inhalt der XML-Eigenschaft aus:
Public Sub KategorienHolen()
Dim objBestellverwaltung As MSXML2.IXMLDOMElement
Dim objKategorie As MSXML2.IXMLDOMElement
Dim objKategorien As MSXML2.IXMLDOMSelection
Dim objDocument As MSXML2.DOMDocument
Set objDocument = GetDocument
Set objBestellverwaltung = objDocument.selectSingleNode("Bestellverwaltung")
Set objKategorien = objBestellverwaltung.selectNodes("Kategorie")
For Each objKategorie In objKategorien
Debug.Print objKategorie.XML
Next objKategorie
End Sub
Da die Ausgabe alle Kategorie-Elemente umfasst, die selbst jeweils einige Artikel-Elemente enthalten, sprengt die Ausgabe das Direktfenster. Also geben wir etwas weniger Umfangreiches aus, indem wir die Debug.Print-Anweisung wie folgt ersetzen und damit gleich noch einen einfachen XPath-Ausdruck nutzen:
Debug.Print objKategorie.selectSingleNode( "Kategoriename").nodeTypedValue
Da wir in diesem Fall nicht einfach den Inhalt der Eigenschaft XML ausgeben wollen, sondern den Inhalt des Elements Kategoriename selbst, verwenden wir die Eigenschaft nodeTypedValue.
Dies war die Leseprobe dieses Artikels.
Melden Sie sich an, um auf den vollständigen Artikel zuzugreifen.