XML lesen mit dem Document Object Model

Mit der Klasse XmlReader, die wir im Artikel “XML-Dokumente schnell lesen mit XmlReader” vorgestellt haben, können Sie XML-Dokumente schnell sequenziell durchlaufen. Dies eignet sich vor allem für den Zugriff auf sehr große XML-Dokumente. Wenn Sie selektiver auf die Inhalte des XML-Dokuments zugreifen wollen, können Sie das Document Object Model nutzen. Implementierungen dieser Schnittstelle, die kurz DOM genannt wird, gibt es für fast alle Programmiersprachen – so auch für die von .NET. Dieser Artikel zeigt, wie Sie die Klassen, Eigenschaften und Methoden des Document Object Models für den Zugriff auf XML-Dokumente nutzen.

DOM im Gegensatz zu XmlReader und XmlWriter

Einer der wichtigsten Unterschiede des Document Object Model im Vergleich zur XmlReader-Klasse ist, dass Sie damit nicht nur lesend, sondern auch schreibend auf die XML-Dokumente zugreifen können. Das heißt, wenn Sie ein Element gefunden haben, dessen Inhalt Sie ändern möchten, dann können Sie das direkt mit den Methoden des Document Object Models erledigen. Sie können damit nicht nur Elemente bearbeiten, sondern auch neue Elemente hinzufügen oder bestehende Elemente löschen. Und natürlich können Sie damit auch komplett neue XML-Dokumente erstellen und mit Daten füllen. Dazu steht allerdings auch die Klasse XmlWriter zur Verfügung, die wir im Artikel XML-Dokumente erstellen mit XmlWriter vorgestellt haben.

Mit dem Document Object Model laden Sie das komplette XML-Dokument in den Speicher, weshalb einzelne Elemente gezielt angesteuert werden können. Während beim XmlReader für alle Elemente die gleichen Eigenschaften abgefragt werden können und je nach Elementtyp mal die eine, mal die andere Eigenschaft Werte zurückliefert, liest das Document Object Model die einzelnen Elemente des XML-Dokuments mit einem entsprechenden Objekttyp ein.

XML-Baum

Intern bildet DOM das XML-Dokument als Baumstruktur ab. Das kann man sich so vorstellen, dass wir ein Stammelement haben, das an der Spitze sitzt. Darunter gibt es dann ein oder mehrere untergeordnete Elemente, die wiederum untergeordnete Elemente haben, bis dann irgendwann Werte in den Elementen stehen – diese landen immer am anderen Ende des Baums. Einen Baum für unser Beispiel-XML-Dokument finden Sie in Bild 1.

Baum eines XML-Dokuments

Bild 1: Baum eines XML-Dokuments

Dieser bildet die aus Platzgründen gekürzte Version des XML-Dokuments aus Bild 2 ab.

Ausschnitt des Dokuments entsprechend dem Baum aus der ersten Abbildung

Bild 2: Ausschnitt des Dokuments entsprechend dem Baum aus der ersten Abbildung

Verweis auf den Namespace System.Xml

Bevor wir ein Objekt auf Basis der Klasse XmlDocument nutzen können, müssen wir einen Verweis auf den folgenden Namespace zur Klasse hinzufügen:

Imports System.Xml

Deklarieren und Initialisieren von XmlDocument

Mit den folgenden beiden Anweisungen deklarieren und initialisieren wir ein Objekt namens objXML mit dem Typ XmlDocument:

Dim objXML As XmlDocument
objXML = New XmlDocument

Laden des XML-Dokuments

Für das Laden eines XML-Dokuments bietet die XmlDocument-Klasse zwei Methoden an:

  • Load: Erwartet den Pfad des zu ladenden XML-Dokuments als Parameter, falls es sich um eine Datei handelt. Sie können auch eine URL angeben. Überladungen erlauben auch das Laden aus einem Stream-, einem TextReader– oder einem XmlReader-Objekt.
  • LoadXml: Erwartet das XML-Dokument als String-Parameter.

Die folgenden Anweisungen erzeugen ein XmlDocument-Objekt, laden das Dokument Bestellverwaltung.xml hinein und geben den Inhalt über die Eigenschaft OuterXml aus:

Dim objXML As XmlDocument
objXML = New XmlDocument
objXML.Load("C:\...\Bestellverwaltung.xml")
Debug.Print(objXML.OuterXml)

Die Ausgabe mit InnerXml liefert für das XmlDocument selbst übrigens das gleiche Ergebnis wie OuterXml.

Fehler beim Einlesen abfangen

Im Gegensatz zur Load-Methode von DOM unter VBA, die einen Boolean-Wert zurückliefert, falls beim Einlesen ein Fehler auftritt, hat die Load-Methode unter VB.NET keinen Rückgabewert. Wenn ein nicht gültiges XML-Dokument geladen wird, köst die Methode schlicht und einfach einen Fehler aus. Diesen können wir jedoch per Try…Catch wie folgt abfangen:

Try
     objXML.Load("C:\...\Bestellverwaltung.xml")
Catch ex As XmlException
     MessageBox.Show("Fehler beim Einlesen:" + vbNewLine + vbNewLine + ex.Message)
End Try

Sie können einen solchen Fehler leicht auslösen, indem Sie einen der Start- oder Endtags aus der Beispieldatei Bestellverwaltung.xml entfernen und dann versuchen, diese einzulesen.

Klassen für die Untersuchung von XML-Dokumenten mit DOM

Die Basisklasse für die Arbeit mit XML-Dokumenten heißt XmlNode. Es gibt einige abgeleitete Klassen, zu denen auch XmlDocument gehört. Das heißt, das XmlNode die grundlegenden Methoden und Eigenschaften bereitstellt und die abgeleiteten Klassen je nach Klasse weitere Elemente. XmlDocument bietet beispielsweise die bereits beschriebenen Methoden Load und LoadXml an. Weitere von XmlNode abgeleitete Klassen sind XmlLinkedNode und XmlAttribute. Von XmlLinkedNode sind weiterhin beispielsweise XmlProcessingInstruction, XmlDeclaration oder XmlElement abgeleitet – sowie die Klasse XmlCharacterData, die wiederum die Basis für Klassen wie XmlComment oder XmlCDATASection bildet.

Das heißt, dass Sie alle Elemente eines XML-Dokuments mit der Klasse XmlNode referenzieren können, aber wenn Sie die spezifischen Methoden und Eigenschaften nutzen wollen, finden Sie den genauen Typ heraus und nutzen diesen.

Nodes durchlaufen mit der ChildNodes-Auflistung

Mit objXML haben wir nun einen Verweis auf das XmlDocument-Objekt selbst. Wie kommen wir nun an die untergeordneten Elemente heran Dafür bietet die XmlNode-Klasse und somit auch die XmlDocument-Klasse die Auflistung ChildNodes an. Wir können zunächst herausfinden, ob XmlDocument überhaupt untergeordnete Elemente hat. Das erledigen wir mit der Eigenschaft HasChildNodes. Sind untergeordnete Elemente vorhanden, können wir über die ChildNodes-Auflistung auf diese zugreifen. Diese bietet mit der Eigenschaft Count die Möglichkeit, die Anzahl zu ermitteln. Im folgenden Beispiel geben wir die Werte von HasChildNodes und ChildNodes.Count aus und durchlaufen dann eine Schleife über alle ChildNode-Elemente. Diese referenzieren wir mit einer Variablen des Typs XmlNode. Das ist wichtig, weil sich in der Auflistung ChildNodes verschiedene Elemente mit von XmlNode abgeleiteten Klassen befinden. Wenn wir eine Variable des Typs XmlElement nutzen, erhalten wir einen Fehler, wenn eines der ChildNode-Elemente etwa den Typ XmlDeclaration hat.

Wir können aber innerhalb der Schleife genau herausfinden, um welchen Typ es sich handelt. Dazu nutzen wir die Eigenschaft NodeType. Außerdem geben wir mit folgenden Zeilen den Namen der untergeordneten Elemente aus:

Dim objNode As XmlNode
Debug.Print (objXML.HasChildNodes)
Debug.Print (objXML.ChildNodes.Count)
For Each objNode In objXML.ChildNodes
     Debug.Print (objNode.Name + " " + objNode.NodeType.ToString)
Next objNode

Das Ergebnis für dieses Beispiel lautet:

xml XmlDeclaration
Bestellverwaltung Element

Damit haben wir also die beiden Elemente der obersten Ebene erfasst, wobei das erste den Typ XmlDeclaration und das zweite den Typ Element hat:

<xml version="1.0" encoding="utf-8">
<Bestellverwaltung>

Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins DATENBANKENTWICKLER:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 200 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar