Galileo Computing < openbook >
Galileo Computing - Bücher zur Programmierung und Softwareentwicklung
Galileo Computing - Bücher zur Programmierung und Softwareentwicklung

...powered by haas.homelinux.net...

Einstieg in VB.NET von René Martin
- Für Programmiereinsteiger -
Einstieg in VB.NET
gp Kapitel 10 XML-Dokumente
  gp 10.1 XML-Grundlagen
  gp 10.2 XML, HTML und XSL – die Ausgabe
    gp 10.2.1 XSL
    gp 10.2.2 Der Aufbau einer XSL-Datei
    gp 10.2.3 Mehrere Kindelemente anzeigen
    gp 10.2.4 Alle Elemente einer Ebene anzeigen
    gp 10.2.5 Attribute auslesen
    gp 10.2.6 STYLE in SPAN und DIV
    gp 10.2.7 Tabellen
    gp 10.2.8 Daten sortieren
    gp 10.2.9 Daten filtern
    gp 10.2.10 Ebenen durchlaufen
    gp 10.2.11 Entscheidungen
    gp 10.2.12 Bilder
    gp 10.2.13 Hyperlinks
    gp 10.2.14 Zusammenfassung von XSL
  gp 10.3 Mit VB.NET nach XML und zurück
    gp 10.3.1 Das DOM
    gp 10.3.2 Ein neues XML-Dokument erzeugen
    gp 10.3.3 Neue Elemente erzeugen
    gp 10.3.4 XML-Dokumente auslesen
    gp 10.3.5 Zugriff auf Attribute
    gp 10.3.6 Durchlaufen von mehreren Ebenen
    gp 10.3.7 Weitere XML-Elemente in VB.NET
    gp 10.3.8 Erzeugen von XML-Objekten und Eigenschaften
    gp 10.3.9 Löschen von Elementen im XML-Dokument
    gp 10.3.10 Transformationen von XML mit dem DOM
    gp 10.3.11 Zusammenfassung VB.NET und XML
  gp 10.4 Ein Beispiel
    gp 10.4.1 Das TreeView-Steuerelement
    gp 10.4.2 Daten werden eingelesen
    gp 10.4.3 Export in eine XML-Datei
  gp 10.5 Zusammenfassung


Galileo Computing

10.3 Mit VB.NET nach XML und zurück  downtop

Im letzten Unterkapitel wurde beschrieben, wie das Dataset-Objekt Daten einer Datenbank hält. Dieses kann nun einfach exportiert werden:

objDataSet.WriteXml("D:\Data\Test.xml")

Der Nachteil ist natürlich, dass über diese Methode nichts eingestellt werden kann.

Etwas flexibler ist die Variante, eine neue Klasse einzurichten, in der einige Members vorhanden sind:

Public Class clsKunde
   Public Geschlecht As String
   Public Vorname As String
   Public Zuname As String
   Public Strasse As String
   Public Plz As String
   Public Ort As String
   Public Infopost As String
End Class

Beachten Sie, dass »Strasse« nicht mit »ß« geschrieben wird, da dieser Name später beim Export als Tag-Name verwendet wird. Füllt nun der Benutzer die Felder aus, werden die Daten in das neue Objekt geschrieben und von dort in eine XML-Datei:

Try
   Dim Kunde As New clsKunde()
   With Kunde
      If Me.radFrau.Checked = True Then
         .Geschlecht = "Frau"
      Else
         .Geschlecht = "Herr"
      End If
      .Vorname = Me.txtVorname.Text
      .Zuname = Me.txtZuname.Text
      .Strasse = Me.txtStraße.Text
      .Plz = Me.txtPLZ.Text
      .Ort = Me.txtOrt.Text
      If Me.chkInfopost.Checked = True Then
         .Infopost = "Wahr"
      Else
         .Infopost = "Falsch"
      End If

      Dim objDatei As _
      New System.IO.FileStream("d:\data\test.xml", _
      IO.FileMode.Create)
      Dim objSerializer As _
      System.Xml.Serialization.XmlSerializer
      objSerializer = New _
      System.Xml.Serialization.XmlSerializer(Kunde.GetType)
      objSerializer.Serialize(objDatei, Kunde)
      objDatei.Close()
   End With
Catch ex As Exception
   MessageBox.Show(ex.Message)
End Try

Es wird eine Datei geöffnet, in die das Objekt »Kunde« geschrieben werden kann (objSerializer.Serialize(objDatei, Kunde)). Um mögliche Attribute zu erkennen, muss der Typ des Objekts bestimmt werden:

System.Xml.Serialization.XmlSerializer(Kunde.GetType)
Abbildung

Abbildung 10.23   Die Datei wird exportiert.

Abbildung

Abbildung 10.24   Danach kann sie weiterverarbeitet werden.

Das Laden funktioniert sogar noch einfacher:

Dim objSerializer As XmlSerializer
Dim objStream As System.IO.FileStream
Dim objGelKunde As clsKunde
objStream = _
   New System.IO.FileStream("D:\Data\test.xml", _
   IO.FileMode.Open)
   objSerializer = New XmlSerializer(GetType(clsKunde))
   objGelKunde = objSerializer.Deserialize(objStream)

With objGelKunde
   If .Geschlecht = "Frau" Then
      Me.radFrau.Checked = True
   Else
      Me.radHerr.Checked = True
   End If
   Me.txtVorname.Text = .Vorname
   Me.txtZuname.Text = .Zuname
   Me.txtStraße.Text = .Strasse
   Me.txtPLZ.Text = .Plz
   Me.txtOrt.Text = .Ort
   If .Infopost = "Wahr" Then
      Me.chkInfopost.Checked = True
   End If
End With
objStream.Close()
End Sub

Wollte man nun mehrere Datensätze laden, ein XML-Dokument durchsuchen oder einzelne Zeilen löschen, empfiehlt es sich, mit dem DOM zu arbeiten.


Galileo Computing

10.3.1 Das DOM  downtop

Zuerst wird deklariert:

Dim xml As Xml.XmlDocument

Die Klasse Xml gehört zu System und könnte selbstverständlich über

Imports.System.Xml

vereinfacht geschrieben werden.

Das Akronym DOM ist nun schon mehrmals aufgetaucht. DOM steht für »Document Object Model«. Damit wird das XML-Dokument wie ein Objekt behandelt und mit Hilfe von Methoden und Eigenschaften werden Informationen ausgelesen und hineingeschrieben. Und damit sind wir beim zweiten zentralen Thema des Buchs.


Galileo Computing

10.3.2 Ein neues XML-Dokument erzeugen  downtop

Da man das XML-Dokument nicht direkt erzeugen will, sondern vom DOM generieren lassen möchte, muss das Dokument initialisiert und gespeichert werden. Die Methode »loadXML« initialisiert das DOM. Dies wird gespeichert, beispielsweise so:

   Dim xml As XML.XmlDocument
   xml = New Xml.XmlDocument()
   xml.loadXML "<Buchliste/>"
   xml.Save _
   "D:\Data\Test.xml"

Soll das XML-Dokument nicht gespeichert, sondern weiterverarbeitet werden, dann speichert die Eigenschaft »OuterXml« die Zeichenkette zwischen. Man könnte also mit dem Meldungsfenster

MessageBox.Show(xml.OuterXml)

das erzeugte XML-Dokument betrachten, ohne es zu speichern.

Wenn Sie die Versionsnummer in das Dokument einfügen möchten, dann können Sie dies wie folgt tun

xml.loadXML "<?xml version='1.0'?><Buchliste/>"

oder Sie stellen die Anführungszeichen durch doppelte Anführungszeichen dar:

xml.loadXML "<?xml version=""1.0""?><Buchliste/>"

Auch eine korrekte Codierung kann vorgenommen werden:

   Dim xml As New XML.XmlDocument
   xml.loadXML "<?xml version=""1.0"" " & _
      "encoding=""ISO-8859-1""?><Buchliste/>"

Eine zweite Variante der korrekten Codierung wird weiter unten mit dem Befehl createProcessingInstruction erläutert.

Abbildung

Abbildung 10.25   Das Dokument mit korrekter PI

In der Datei befindet sich lediglich der Tag <Buchliste/>. Damit ist das Dokument sogar wohlgeformt, wie man leicht zeigen kann. Der Befehl

xml.documentElement.Name

liefert den korrekten Namen des Wurzelelements »Buchliste«. Wäre kein Wurzelelement vorhanden (was gegen die Gültigkeitsregeln eines XML-Dokuments verstößt), dann würde »Null« zurückgegeben werden. Will man dagegen eine vorhandene Datei öffnen (und nicht neu anlegen), so kann die Methode Load verwendet werden. Der Einfachheit halber wurde der Dateipfad auf die Konstante PFAD gelegt:

   xml.Load(PFAD)

Das Wurzelelement ist die schreibgeschützte Eigenschaft documentElement. Ihren Namen (Name) kann man auslesen.

Tabelle 10.6   Die wichtigsten Methoden und Eigenschaften des XmlDocuments
Methoden und Eigenschaften der Klasse DOMDocument Erläuterung
load lädt ein XML-Dokument aus einer Datei
loadXML lädt ein XML-Dokument aus einer Zeichenkette
save speichert das DOM als XML-Datei
xml der Textinhalt des XML-Dokuments


Galileo Computing

10.3.3 Neue Elemente erzeugen  downtop

Man kann mit Hilfe des DOM neue Elemente im XML-Dokument generieren lassen. Dazu wird deklariert

   Dim xmlKD As Xml.XmlDomElement

und anschließend erzeugt:

   xmlKD = xml.createElement("Artikel")

Das Erzeugen alleine genügt noch nicht – das neue Element muss noch angehängt werden:

   xml.documentElement.appendChild(xmlKD)

Die folgende Prozedur

Sub Zugriff_Auf_XML01()
   Dim xml As New XML.XmlDocument()
   Dim xmlKD As.Xml.XmlElement
   
   xml.load(PFAD) 
   xmlKD = xml.createElement("Artikel")
   xml.documentElement.appendChild(xmlKD)
   xml.Save(PFAD)
End Sub

erzeugt das folgende XML-Dokument:

<Buchliste>
   <Artikel/>
</Buchliste>

Der Tag Artikel ist (noch) leer. Soll er gefüllt werden, so muss der Inhalt über ein Textelement hinzugefügt werden:

Sub Zugriff_Auf_XML01()
   Dim xml As New XML.XmlDocument()
   Dim xmlKD As.Xml.XmlNode
   Dim xmlText As Xml.XmlText
   
   xml.load(PFAD) 
   xmlKD = xml.createElement("Artikel")
   xmlText = xml.CreateTextNode("VB.net lernen")
   xmlKD.AppendChild(xmlText)
   xml.documentElement.appendChild(xmlKD)
   xml.Save(PFAD)
End Sub

Das Ergebnis sieht nun bekannt aus:

<Buchliste>
   <Artikel/>VB.net lernen<Artikel/>
</Buchliste>

Beachten Sie, dass xmlKD nicht mehr als »XmlElement« deklariert wurde, sondern als »XmlNode«. Ebenso können weitere Elemente eingelesen werden:

 [...]
   xmlKD = xml.createElement("Artikel")
   xmlText = xml.CreateTextNode("VB.net - " & _
   "Objektorientiertes Programmieren")
   xmlKD.AppendChild(xmlText)
   xml.documentElement.appendChild(xmlKD)

   xmlKD = xml.createElement("Artikel")
   xmlText = xml.CreateTextNode("VISUAL BASIC.net")
   xmlKD.AppendChild(xmlText)
   xml.documentElement.appendChild(xmlKD)
 [...]
Abbildung

Abbildung 10.26   Das XML-Dokument wächst.

Und selbstverständlich auch Unterelemente:

Sub Zugriff_Auf_XML04()
   Dim xml As New Xml.XmlDocument()
   Dim xmlKD As Xml.XmlElement
   Dim xmlUnterKD1 As Xml.XmlElement
   Dim xmlUnterKD2 As Xml.XmlElement
   Dim xmlText As Xml.XmlText
   xml.LoadXml("<?xml version='1.0' " & _
   "encoding=""ISO-8859-1""?><Buchliste/>")

   xmlKD = xml.CreateElement("Artikel")
   xmlUnterKD1 = xml.CreateElement("Titel")
   xmlUnterKD2 = xml.CreateElement("Autor")
   xmlText = xml.CreateTextNode("VB.net lernen")
   xmlUnterKD1.AppendChild(xmlText)
   xmlText = xml.CreateTextNode("Rene Martin")
   xmlUnterKD2.AppendChild(xmlText)
   xmlKD.AppendChild(xmlUnterKD1)
   xmlKD.AppendChild(xmlUnterKD2)
   xml.DocumentElement.AppendChild(xmlKD)

   xmlKD = xml.CreateElement("Artikel")
   xmlUnterKD1 = xml.CreateElement("Titel")
   xmlUnterKD2 = xml.CreateElement("Autor")
   xmlText = xml.CreateTextNode("VB.net - " & _
   "Objektorientiertes Programmieren")
   xmlUnterKD1.AppendChild(xmlText)
   xmlText = xml.CreateTextNode("Andreas Kühnel")
   xmlUnterKD2.AppendChild(xmlText)
   xmlKD.AppendChild(xmlUnterKD1)
   xmlKD.AppendChild(xmlUnterKD2)
   xml.DocumentElement.AppendChild(xmlKD)

   xmlKD = xml.CreateElement("Artikel")
   xmlUnterKD1 = xml.CreateElement("Titel")
   xmlUnterKD2 = xml.CreateElement("Autor")
   xmlText = xml.CreateTextNode("VISUAL BASIC.net")
   xmlUnterKD1.AppendChild(xmlText)
   xmlText = xml.CreateTextNode("Peter Monadjemi")
   xmlUnterKD2.AppendChild(xmlText)
   xmlKD.AppendChild(xmlUnterKD1)
   xmlKD.AppendChild(xmlUnterKD2)
   xml.DocumentElement.AppendChild(xmlKD)

   xml.Save(PFAD)
End Sub

Das Ergebnis gestaltet sich wie folgt:

Abbildung

Abbildung 10.27   Das aktuelle XML-Dokument

Und so können problemlos neue Elemente an ein bestehendes XML-Dokument angefügt werden:

Sub NeuesElement()
   Dim xml As New Xml.XmlDocument()
   Dim xmlKD As Xml.XmlElement
   Dim xmlUnterKD1 As Xml.XmlElement
   Dim xmlUnterKD2 As Xml.XmlElement
   Dim xmlText As Xml.XmlText
   xml.Load(PFAD)

   xmlKD = xml.CreateElement("Artikel")
   xmlUnterKD1 = xml.CreateElement("Titel")
   xmlUnterKD2 = xml.CreateElement("Autor")
   xmlText = xml.CreateTextNode("Einstieg in XML")
   xmlUnterKD1.AppendChild(xmlText)
   xmlText = xml.CreateTextNode("Helmut Vonhoegen")
   xmlUnterKD2.AppendChild(xmlText)
   xmlKD.AppendChild(xmlUnterKD1)
   xmlKD.AppendChild(xmlUnterKD2)
   xml.DocumentElement.AppendChild(xmlKD)

   xml.Save(PFAD)
End Sub
Abbildung

Abbildung 10.28   Am Ende des Dokuments wird ein neues Element hinzugefügt.


Galileo Computing

10.3.4 XML-Dokumente auslesen  downtop

Und damit steht schon fast das Gerüst, mit dessen Hilfe die XML-Datei ausgelesen werden kann. Zuerst wird der Name des Wurzelelements ermittelt. Das funktioniert mit dem Befehl load:

   xml.Load "c:\Eigene Dateien\XML\test.xml"

Dann kann so auf das Wurzelelement zugegriffen werden

   Dim strWurzel As String
   strWurzel = xml.documentElement. Name

oder auch so, wenn keine PI vorhanden ist:

   strWurzel = xml.childNodes(0).Name

Und wie viele Elemente besitzt das Wurzelelement? Die Anzahl wird mit count bestimmt:

   xml.documentElement.childNodes.Count

Auf die Elemente kann einzeln zugegriffen werden:

   For intZähler = 0 To _
      xml.documentElement.childNodes.Count - 1
      MsgBox xml.documentElement.childNodes(intZähler).Value
   Next

Achtung: Die Zählung beginnt bei 0!

Die Eigenschaft »Count« ist wichtig, da man mit ihrer Hilfe ermitteln kann, ob überhaupt Kindelemente (oder Attribute) vorhanden sind. Alternativ kann die Methode »hasChildNodes« verwendet werden.

Da das Tag »Buch« zwei Unterelemente besitzt, nämlich »Artikelname« und »Warenhauptgruppe«, werden sämtliche – in diesem Fall beide – Texte ausgelesen und aneinander gehängt. Um dies zu vermeiden, wird eine weitere Schleife benötigt, die auf jedes Element zugreift:

   For lngZähler = 0 To _
      xml.documentElement.childNodes.Count - 1
      For lngUnterZähler = 0 To _
         xml.documentElement.childNodes(lngZähler). _
         childNodes.Count - 1
        MsgBox xml.documentElement.childNodes(lngZähler). _
            childNodes(lngUnterZähler).Value
      Next lngUnterZähler
   Next lngZähler

Galileo Computing

10.3.5 Zugriff auf Attribute  downtop

Auf diese Weise können ebenfalls Attribute ausgelesen werden. Das folgende Beispiel liefert den Namen des Attributs (»Preis«):

   xmlKD = xml.documentElement.childNodes(0)
   dblPreis = xmlKD.Attributes(0).Value

Oder man durchläuft mit einer Schleife alle Elemente und greift sich den Wert des Attributs heraus:

   For Each xmlKD In xml.documentElement.childNodes
         dblPreis += xmlKD.Attributes(0).Value
   Next xmlKD
   ' -- die Attribute werden ermittelt

Wenn man die Namen der Attribute kennt, so kann man über ihren Namen getAttribute mit der Methode auf sie zugreifen

   xmlKD.getAttribute("Preis")

oder den Namen ermitteln lassen:

   strAttributname = xmlKD.Attributes(0). Name
   strAttributInhalt = _ 
   xmlKD.getAttribute(strAttributname).Value
Tabelle 10.7   Weitere Methoden und Eigenschaften der Klasse XmlDocument
Methoden und Eigenschaften der Klasse DOMDocument Erläuterung
documentElement das Wurzelelement
createElement erzeugt ein neues Element

Tabelle 10.8   Die wichtigsten Methoden und Eigenschaften der Klasse XmlElement
Methoden und Eigenschaften der Klasse XmlElement Erläuterung
appendChild hängt ein neues Element an
length die Anzahl der Elemente einer Liste
text Inhalt des Elements
Name der Name des Elements oder Attributs
Value der Name des Knotens (entspricht baseName)
setAttribute setzt den Wert eines Attributs
getAttribute liest den Wert des Attributs
getAttributeNode das Attribut wird als Objekt zurückgegeben
item ein Element der Liste alternative Schreibweisen sind: xml.documentElement.childNodes(0) xml.documentElement.childNodes.item(0)


Galileo Computing

10.3.6 Durchlaufen von mehreren Ebenen  downtop

Schwieriger wird es, wenn keine oder keine vollständigen Informationen über das XML-Dokument vorliegen, wenn also nicht bekannt ist, wie viele Ebenen das Dokument verwendet. Dann muss es von der ersten bis zur letzten Ebene durchlaufen werden. Eine Abfrage überprüft, ob es sich bei einem Element um einen Knoten handelt. Falls ja, wird diese Prozedur erneut aufgerufen. Falls nein, wird der Text des Elements aufgerufen. Diese Funktion, die sich selbst aufruft, wird von außen angestoßen und verwendet sich selbst als Möglichkeit. Dies könnte so aussehen:

Sub MeinEigenesXML()
   Dim xml As New Xml.XmlDocument
   Dim xmlElement As Xml.XmlElement
   
   xml.Load "C:\Eigene Dateien\Visio\Kapitel16\test08.xml"
   strText = xml.documentElement.baseName & vbCr
   
   xmlElement = xml.documentElement
   
   Call XMLDurchlauf(xmlElement)
   
   MessageBox.Show(strText)
End Sub

Sub XMLDurchlauf(ByVal xmlElement As Xml.XmlElement)
   Dim i As Integer
   For i = 0 To xmlElement.childNodes.Length - 1
      With xmlElement.childNodes(i)
         If .nodeType = Xml.XmlNodeType.Element Then
            strText = strText & _
            xmlElement.childNodes(i).nodeName & ": "
            XMLDurchlauf xmlElement.childNodes(i)
         ElseIf .nodeType = Xml.XmlNodeType.Text Then
             strText = strText & . Value & vbCr
         Else
             strText = strText & " ** ?? ** "
         End If
      End With
   Next i
End Sub
Abbildung

Abbildung 10.29   Das Ergebnis nach den Zugriff auf eine »beliebige« Datei

Hier wurden folgende Eigenschaften verwendet:

Tabelle 10.9   Der erste, letzte, vorhergehende, nächste und darüber liegende Knoten
Eigenschaften des Wurzelelements und der Knoten Erläuterung
firstChild das erste Kindelement
lastChild das letzte Kindelement
previousSibling der vorhergehende Knoten
nextSibling der nächste Knoten
parentNode der direkte Vorfahre (das Dokument selbst besitzt keinen parentNode, der parentNode des Wurzelknotens ist leer)


Galileo Computing

10.3.7 Weitere XML-Elemente in VB.NET  downtop

Anhand einiger Beispiele werden systematisch die Eigenschaften und Methoden der Objektbibliothek XML aufgelistet.

Gegeben sei ein XML-Dokument mit folgender Gestalt:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- **** Dieses Dokument ist für die deutsche Sprache geeignet 
und folgt den Konventionen der Version 1.0. **** -->
<!DOCTYPE Autorenliste [
   <!ELEMENT Autorenliste (Autor)+>
      <!ELEMENT Autor (Zuname, Vorname)+>
         <!ELEMENT Zuname (#PCDATA)>
         <!ELEMENT Vorname (#PCDATA)>
   <!ATTLIST Autorenliste Status CDATA #IMPLIED>
]>
<Autorenliste Status="Öffentlich">
   <Autor>
      <Zuname>Hofstadter</Zuname>
      <Vorname>Douglas R.</Vorname>
   </Autor>
   <Autor>
      <Zuname>Gardner</Zuname>
      <Vorname>Martin</Vorname>
   </Autor>
   <Autor>
      <Zuname>Ifrah</Zuname>
      <Vorname>Georges</Vorname>
   </Autor>
</Autorenliste>
Abbildung

Abbildung 10.30   Ein einfaches Dokument

Geladen wird es mit

   x0.Load("D:\Data\Liste.xml")

wenn x0 deklariert wurde:

   Dim x0 As New Xml.XmlDocument

Der DTD entspricht das Objekt »doctype« – eine Eigenschaft des Dokuments. Man kann beispielsweise den Inhalt mit

MessageBox.Show(x0.DocumentType.Name

auslesen. Allerdings ist dieses Objekt schreibgeschützt. Es ist also nicht möglich, per Programmierung der Dokumente eine DTD hinzuzufügen. Würde ein Namensraum verwendet werden, dann könnte man dies mit der Eigenschaft

namespaceURI

ermitteln:

   If x0.namespaceURI.ToString = "" Then
      MessageBox.Show("Kein Namensraum angegeben.")
   Else
      MessageBox.Show("Der Namensraum lautet: " & _
      x0.namespaceURI.ToString)
   End If

Auch diese Eigenschaft ist, wie die DTD, schreibgeschützt. Existiert ein Namensraum, so wird das Präfix mit der Eigenschaft »prefix« herausgelöst.

Das Dokument selbst besitzt vier Knoten, wie mit der Eigenschaft

   x0.childNodes.Count

leicht ermittelt werden kann. Jeder Knoten besitzt die Eigenschaft »nodeType«, über welche er näher bestimmt werden kann.

Tabelle 10.10   Die verschiedenen Knotenarten
Knotentyp Nummer
None 0
Element 1
Attribute 2
Text 3
CDATA 4
EntityReference 5
Entity 6
ProcessingInstruction 7
Comment 8
Document 9
DocumentType 10
DocumentFragment 11
Notation 12
Whitespace 13
SignificantWhitespace 14
EndElement 15
EndEntity 16
XmlDeclaration 17

Diese Liste finden Sie auch in der Hilfe. Diese Eigenschaft ist schreibgeschützt, was bedeutet, dass man nicht per Programmierung den Typ ändern kann, was vernünftig ist. Mit der Eigenschaft »nodeType« kann überprüft werden:

Dim x0 As New Xml.XmlDocument()
Dim xmlKnoten As Xml.XmlNode
Dim x1 As Xml.XmlElement
Dim x2 As Xml.XmlAttribute
Dim x3 As Xml.XmlText
Dim x4 As Xml.XmlCDataSection
Dim x5 As Xml.XmlEntityReference
Dim x6 As Xml.XmlEntity
Dim x7 As Xml.XmlProcessingInstruction
Dim x8 As Xml.XmlComment
Dim x9 As Xml.XmlDocument
Dim x10 As Xml.XmlDocumentType
Dim x11 As Xml.XmlDocumentFragment
Dim x12 As Xml.XmlNotation
Dim x17 As Xml.XmlDeclaration

Dim strAusgabe As String

x0.Load("D:\Data\Liste.xml")

For Each xmlKnoten In x0.childNodes
   Select Case xmlKnoten.nodeType
      Case Xml.XmlNodeType.Element, _
         Xml.XmlNodeType.EndElement
         x1 = xmlKnoten
         strAusgabe = x1.Name & ": " & vbCr & x1.InnerText
      Case Xml.XmlNodeType.Attribute
         x2 = xmlKnoten
         strAusgabe = x2.Name & ": " & vbCr & x2.InnerText
      Case Xml.XmlNodeType.Text
         x3 = xmlKnoten
         strAusgabe = x3.Name & ": " & vbCr & x3.InnerXml
      Case Xml.XmlNodeType.CDATA
         x4 = xmlKnoten
         strAusgabe = x4.Name & ": " & vbCr & x4.InnerXml
      Case Xml.XmlNodeType.EntityReference
         x5 = xmlKnoten
         strAusgabe = x5.Name & ": " & vbCr & x5.InnerXml
      Case Xml.XmlNodeType.Entity
         x6 = xmlKnoten
         strAusgabe = x6.Name & ": " & vbCr & x6.InnerXml
      Case Xml.XmlNodeType.ProcessingInstruction
         x7 = xmlKnoten
         strAusgabe = x7.InnerXml
      Case Xml.XmlNodeType.Comment
         x8 = xmlKnoten
         strAusgabe = x8.Value
      Case Xml.XmlNodeType.Document
         x9 = xmlKnoten
         strAusgabe = x9.Name & ": " & vbCr & x9.InnerXml
      Case Xml.XmlNodeType.DocumentType
         x10 = xmlKnoten
         strAusgabe = x10.Name
      Case Xml.XmlNodeType.DocumentFragment
         x11 = xmlKnoten
         strAusgabe = x11.Name & ": " & vbCr & x11.InnerXml
      Case Xml.XmlNodeType.Notation
         x12 = xmlKnoten
         strAusgabe = x12.Name & ": " & vbCr & x12.InnerXml
      Case Xml.XmlNodeType.XmlDeclaration
         x17 = xmlKnoten
         strAusgabe = x17.Name
      Case Else
         strAusgabe = "Unbekannter Knoten"
   End Select
   MessageBox.Show(xmlKnoten.GetType.ToString & ":" & _
   vbCr & strAusgabe)
Next
Abbildung

Abbildung 10.31   Die XML-Deklaration wird ausgelesen.

Abbildung

Abbildung 10.32   Der Kommentar wird ausgelesen.

Abbildung

Abbildung 10.33   Das Wurzelelement wird ausgelesen.

Abbildung

Abbildung 10.34   Die Kindelemente werden ausgelesen.

Im obigen Beispiel werden die Inhalte der vier Knoten x17, x8, x10 und x1 ausgegeben: »xml version=»1.0« encoding=»ISO-8859-1««, »**** Dieses Dokument ist für die deutsche Sprache geeignet und folgt den Konventionen der Version 1.0. ****«, »Autorenliste« und »Autorenliste: Hofstadter Douglas R. Gardner Martin Ifrah Georges«.

Statt InnerText kann vielfach auch InnerXml verwendet werden. Dann werden allerdings auch die Namen der Tags mit ausgelesen.

Wenn Sie lieber mit Zeichenketten arbeiten, dann können Sie den Typ des Knotens als String mit der Eigenschaft nodeType.ToString oder getType.To-String ermitteln. Dabei stehen die Werte zur Verfügung, die Sie in obiger Tabelle aufgelistet finden.

Übrigens ist in der XML-Spezifikation vorgesehen, dass alle Leerräume erhalten bleiben. Besonders für Kommentare ist dies wichtig, wenn sie aus mehreren Wörtern bestehen. Soll dies explizit festgelegt (oder unterbunden) werden, dann ist hierfür die Eigenschaft preserveWhiteSpace verantwortlich. Wird sie auf »True« gesetzt, dann bleiben alle Leerräume, das heißt alle Leerzeichen, Tabulatoren, Absatzwechsel und Zeilenschaltungen, erhalten.


Galileo Computing

10.3.8 Erzeugen von XML-Objekten und Eigenschaften  downtop

Mit den beiden Objekten »Element« und »Node« können neue Elemente erzeugt und mit Eigenschaften versehen werden:

Dim xml As New Xml.XmlDocument()
Dim xmlKD As Xml.XmlElement
Dim xmlUnterKD1 As Xml.XmlElement
Dim xmlUnterKD2 As Xml.XmlElement
Dim xmlText As Xml.XmlText
xml.Load(PFAD2)

xmlKD = xml.CreateElement("Autor")
xmlUnterKD1 = xml.CreateElement("Zuname")
xmlUnterKD2 = xml.CreateElement("Vorname")
xmlText = xml.CreateTextNode("Hawkins")
xmlUnterKD1.AppendChild(xmlText)
xmlText = xml.CreateTextNode("Steve")
xmlUnterKD2.AppendChild(xmlText)
xmlKD.AppendChild(xmlUnterKD1)
xmlKD.AppendChild(xmlUnterKD2)
xml.DocumentElement.AppendChild(xmlKD)

xml.Save(PFAD2)
Abbildung

Abbildung 10.35   Vorher ...

Abbildung

Abbildung 10.36   ... und danach

Damit der Pfad beim Speichern nicht ein zweites Mal hergeholt werden muss, kann der Speicherort mit der Eigenschaft »BaseURI« ermittelt werden.

Da nicht sicher ist, ob ein Element ein Attribut besitzt, muss überprüft werden, ob die Eigenschaft »Attributes.Count > 0« vorliegt. Falls ja, kann auf jedes Attribut zugegriffen werden. Auch hier kann wieder mit einer Objektvariablen vom Typ Xml.XmlAttribute gearbeitet werden:

   Dim x0 As New Xml.XmlDocument()
   Dim x1 As Xml.XmlElement
   Dim x2 As Xml.XmlAttribute

   Dim strAusgabe As String

   x0.Load "D:\Data\Liste.xml"
   x1 = x0.documentElement
   If x1.Attributes.Count > 0 Then
      For Each x2 In x1.Attributes
         strAusgabe = strAusgabe & vbCr & _
            x2. Name & ": " & x2.Value
      Next
   MessageBox(strAusgabe)
   End If
Abbildung

Abbildung 10.37   Das Attribut (alle Attribute) mit Name und Inhalt

Das Objekt DOMDocument besitzt einige »Create«-Methoden. Mit der korrekten Variablendeklaration kann an eine Objektvariable das entsprechende Objekt übergeben werden. Folgende Typen stehen hierbei zur Verfügung:

   Dim x0 As New Xml.XmlDocument
   Dim x1 As Xml.XmlAttribute
   Dim x2 As Xml.XmlCDATASection
   Dim x3 As Xml.XmlComment
   Dim x4 As Xml.XmlDocumentFragment
   Dim x5 As Xml.XmlElement
   Dim x6 As Xml.XmlEntityReference
   Dim x7 As Xml.XmlNode
   Dim x8 As Xml.XmlProcessingInstruction
   Dim x9 As Xml.XmlText

Sie werden gesetzt:

   x1 = x0.createAttribute
   x2 = x0.createCDATASection
   x3 = x0.createComment
   x4 = x0.createDocumentFragment
   x5 = x0.createElement
   x6 = x0.createEntityReference
   x7 = x0.createNode
   x8 = x0.createProcessingInstruction
   x9 = x0.createTextNode

Alle oben aufgelisteten Methoden verlangen eine Zeichenkette. Einige sind überladen, das heißt, man kann neben dem Namen auch noch einen Namespace eingeben (beispielsweise Elemente oder Attribute). Einige Methoden verlangen mehrere Attribute – wie zum Beispiel »CreateXmlDeclaration« –, wie die Version, das Encoding und die Option »standallone« eingegeben werden muss.

Das Hinzufügen von neuen Knoten umfasst immer zwei Phasen: Zuerst muss ein Knoten erzeugt werden. Dann wird der Knoten an das korrekte Elternelement angehängt. Bei den meisten create-Methoden funktioniert es auf die gleiche Weise, lediglich Attribute werden etwas anders angehängt.

Das folgende Beispiel illustriert das Vorgehen:

Sub NeueElemente()
   Dim x0 As New Xml.XmlDocument
   
   Dim x1 As Xml.XmlDeclaration
   Dim x2 As Xml.XmlComment
   Dim x3 As Xml.XmlElement
   Dim x4 As Xml.XmlAttribute
   Dim x5 As Xml.XmlNode
   Dim x6 As Xml.XmlCDATASection
   Dim x7 As Xml.XmlText
   
   Dim x8 As Xml.XmlDocumentFragment
   Dim x9 As Xml.XmlEntityReference

Ein leeres Dokument wurde erzeugt. Im ersten Schritt wird das Wurzelelement eingefügt:

   x3 = x0.createElement("Wurzel")
   x0.appendChild(x3)

Es fehlt die Processing Instruction. Da sie vor dem Wurzelelement steht, muss sie im InsertBefore in das Dokument hineingeschrieben werden. Beachten Sie, dass der Parameter Standallone »yes« sein muss. Target liegt lediglich in der Version 1.0 vor.

   x1 = x0.createXmlDeclaration _
      ("1.0", "ISO-8859-1", "yes")
   x0.InsertBefore(x1, x0.DocumentElement)

Anschließend wird ein Kommentar erzeugt und eingefügt:

   x2 = x0.createComment _
      ("Dieses Beispiel dient lediglich dazu, " & _
      "die create-Methoden zu zeigen.")
   x0.appendChild(x2)

Danach wird das Wurzelelement erzeugt und in das XML-Dokument eingefügt.

Ein Attribut wird erzeugt. Es besteht aus Attributname (»Eigenschaft«) und Wert (»feucht, lang, dunkel und braun«). Beachten Sie, dass das Attribut nicht mit der Methode appendChild hinzugefügt wird, sondern mit der Methode setNamedItem an die Sammlung »Attributes« angehängt wird:

   x4 = xml.createAttribute("Eigenschaft")
   x4.Value = "feucht, lang, dunkel und braun"
   x3.Attributes.setNamedItem(x4)

Man kann übrigens ein Attribut leichter mit der Methode setAttribute anhängen. Diese Methode verlangt zwei Parameter, Name und Value:

   x3.setAttribute("Eigenschaft2", "unter der Erde")

Schließlich wird ein Knoten erzeugt und an das Wurzelelement angefügt:

   x5 = x0.createNode(Xml.XmlNodeType.Element, "Knoten", "")
   x3.appendChild(x5)

Danach wird ein CDATA-Abschnitt erzeugt, der Zeichendaten enthält, die nicht geparst werden (»>>«). Dieser Abschnitt wird an den Knoten angehängt:

   x6 = x0.createCDATASection(">>")
   x5.appendChild(x6)

Dem Knoten wird ein Inhalt zugewiesen:

   Set x7 = xml.createTextNode("und ich bin der Inhalt")
   x5.appendChild x7

Knoten können auch auf andere Weise erzeugt werden. Der Textinhalt kann als Eigenschaft des Knotens gesehen werden:

   Set x5 = xml.createNode(Xml.XmlNode.Element, "Knoten", "")
   x5.InnerText = "ich bin der zweite Inhalt"
   x3.appendChild(x5)

Wer es lieber kurz und bündig (englisch: »quick and dirty«) haben möchte, der kann es auch wie folgt schreiben:

   x3.appendChild(x0.createElement("Knoten")).AppendChild = _
   (CreateTextNode("ich bin der vierte Knoten")))

Die vorhergehenden Schreibweisen sind sicherlich übersichtlicher. Vergessen Sie nicht, das gesamte Dokument zu speichern!

   x0.Save("D:\Data\NeueListe.xls")
End Sub
Abbildung

Abbildung 10.38   Das Ergebnis des XML-Dokuments, das mit VB.NET erzeugt wurde


Galileo Computing

10.3.9 Löschen von Elementen im XML-Dokument  downtop

Elemente können neu erzeugt, aber auch gelöscht werden:

   x1.removeAttribute("Att1")
   x1.removeAttributeNode(x2)
   x1.removeChild(x3)

Beachten Sie, dass das Dokument danach wieder gespeichert werden muss!


Galileo Computing

10.3.10 Transformationen von XML mit dem DOM  downtop

Manchmal ist es nötig, dass automatisch generierte Dokumente in ihrem Inhalt oder in ihrer Struktur verändert werden. Auch dies kann mit einigen VB.NET-Befehlen, oder genauer: mit dem DOM, erledigt werden. Welche Möglichkeiten VB.NET zur Verfügung stellt und wie sie angewendet werden, wird in diesem Kapitel beschrieben. Ein ganz einfaches Beispiel könnte der XML-Export von Excel darstellen. Wenn Sie eine Excel-Mappe als XML-Datei speichern, schreibt der Filter zu viele Daten in diese Datei. Um nur die gewünschten Daten zu erhalten beziehungsweise um sie in einer bestimmten Form zu haben, könnte diese exportierte Datei transformiert werden, damit sie die passende Gestalt hat.

Mit Hilfe von appendChild können Elemente an das Wurzelelement oder an andere Elemente angefügt werden:

   Dim xml As New Xml.XmlDocument
   Dim xmlElement As Xml.Xmllement
   xml.Load("D:\Data\test01.xml")
   Set xmlElement = xml.createElement("NeuesElement")
   xml.documentElement.appendChild(xmlElement).Value = _
      "Hallo, ist noch wer da?"
   xml.Save("D:\Data\test02.xml")

Analog kann das Element mit der Methode removeChild gelöscht werden:

   Dim xml As New Xml.XmlDocument
   Dim xmlElement As Xml.XmlElement
   xml.Load("D:\Data\test02.xml")
   xmlElement = xml.documentElement.lastChild
   xml.documentElement.removeChild(xmlElement)
   xml.Save("D:\Data\test02.xml")

Die Methode appendChild setzt das neue Element immer ans Ende der Knotenliste. Soll es an eine bestimmte Position gesetzt werden, dann kann die Methode InsertBefore verwendet werden. Beide Methoden geben einen Knoten zurück. Im folgenden Beispiel wird das neue Element am Anfang des Wurzelelements eingefügt:

   Dim xml As New Xml.XmlDocument()
   Dim xmlElement As Xml.XmlElement
   xml.Load("D:\Data\test04.xml") _
   xmlElement = xml.createElement("NeuesElement")
   xml.documentElement.InsertBefore(xmlElement, _
   xml.documentElement.childNodes(0)).InnerText = _
      "Hallo, ist noch wer da?"
   xml.Save("D:\Data\test02.xml"))

Fasst man die beiden Methoden insertBefore und removeChild zusammen, dann kann man damit leicht ein Element ersetzen:

Sub Ersetze01(xmlBossElement As Xml.XmlElement, _
   xmlAltesElement As Xml.Xmllement, _
   xmlNeuesElement As Xml.XmlElement)

   xmlBossElement.insertBefore(xmlNeuesElement, _
      xmlAltesElement)
   xmlBossElement.removeChild(xmlAltesElement)
End Sub

Diese Prozedur wird von anderer Stelle aufgerufen, beispielsweise so:

Sub XML_Bewegung01()
   Dim xml As New Xml.XmlDocument()
   Dim xmlElementErstes As Xml.XmlElement
   Dim xmlElementLetztes As Xml.XmlElement
   xml.Load("D:\Data\test02.xml")
   xmlElementLetztes = xml.documentElement.LastChild
   xmlElementErstes = xml.documentElement.FirstChild
   
   Call Ersetze01(xml.documentElement, xmlElementErstes, _
      xmlElementLetztes)
   xml.Save("D:\Data\test02.xml")
End Sub

Es geht aber mit der Methode replaceChild eleganter:

Sub Ersetze02(xmlBossElement As Xml.XmlElement, _
   xmlAltesElement As Xml.XmlElement, _
   xmlNeuesElement As Xml.XmlElement)
   
   xmlBossElement.replaceChild(xmlNeuesElement, _
      xmlAltesElement)
End Sub

Achtung: Das XML-Dokument muss bei der Methode replaceChild mindestens drei Elemente haben. Dagegen arbeitet die selbst definierte Prozedur »Ersetze01« auch mit zwei, ja sogar mit einem Element, welches nach Ablauf gelöscht ist. Während mit insertBefore ein Knoten verschoben wird, kann mit der Methode cloneNode ein Knoten kopiert werden:

Sub KopiereKnoten(xmlBossElement As Xml.XmlElement, _
   xmlAltesElement As Xml.XmlElement)
   Dim xmlNeuesElement As Xml.XmlElement
   
   Set xmlNeuesElement = xmlAltesElement.CloneNode(True)
   xmlBossElement.appendChild xmlNeuesElement
End Sub

Die Methode cloneNode verlangt einen Parameter deep (»True« oder »False«), der festlegt, ob die Kindknoten mitgeklont werden oder nicht.

Mit dieser Prozedur wird der letzte Knoten dupliziert und steht nun zweimal hintereinander im XML-Dokument. Soll er dagegen am Ende und am Anfang stehen, dann ist der Code um folgende Zeile zu erweitern:

   xmlBossElement.insertBefore(xmlNeuesElement, _
      xmlBossElement.childNodes(0))

Vielleicht mag der eine oder andere Leser nun erstaunt kommentieren, dass XML-Transformationen ja eine lustige Sache sind, aber möglicherweise keinen praktischen Sinn haben. Denn wenn ein XML-Dokument erzeugt wurde, so kann man beim Erzeugen schon auf die Daten und auf die Ebene in der Hierarchie achten, in welcher sich die Daten befinden. Kann man das immer? Was ist, wenn Sie von anderen Menschen oder Maschinen XML-Dokumente erhalten, die Ihnen in dieser Form nicht »gefallen«? Die Microsoft-Programme sind gute Beispiel für die Notwendigkeit der XML-Transformation. Wenn Sie eine Zeichnung aus Visio oder eine Tabelle aus Excel ins XML-Format exportieren, dann werden zu viele Informationen weggeschrieben, die gar nicht benötigt werden. Um dies zu verhindern oder auszugleichen, kann ein XML-Dokument in seinem Inhalt und in seiner Struktur manipuliert werden. Mit Hilfe der DOM-Transformationen können Daten restrukturiert werden.


Galileo Computing

10.3.11 Zusammenfassung VB.NET und XML  toptop

Manchmal müssen automatisch generierte Dokumente in ihrem Inhalt oder in ihrer Struktur verändert werden. Nicht immer können XML-Dateien von Grund auf geplant und angelegt werden.

Dies kann mit einigen VB.NET-Befehlen beziehungsweise mit dem DOM, erledigt werden. Welche Möglichkeiten VB.NET hierzu zur Verfügung stellt und wie sie angewendet werden, wurde in diesem Kapitel vorgestellt. An einem Beispiel soll nun gezeigt werden, wie Daten aus einer Excel-Tabelle herausgeholt werden, nach XML geschrieben und mit einer XSL(T)-Datei verknüpft werden, damit sie im Browser die gewünschte Gestalt haben.

  

VB.NET

Einstieg in ASP.NET

Einstieg in C#

Visual C#

VB.NET und Datenbanken

Einstieg in XML