{"id":55000970,"date":"2015-02-01T00:00:00","date_gmt":"2020-05-22T21:06:56","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=970"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"SAX_XMLDokumente_parsen_in_der_Praxis","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/SAX_XMLDokumente_parsen_in_der_Praxis\/","title":{"rendered":"SAX: XML-Dokumente parsen in der Praxis"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg07.met.vgwort.de\/na\/f7e77357a48747388217f3793fb29747\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p><b>Im Beitrag XML-Dokumente mit SAX parsen haben wir die Grundlagen ds SAX-Parsers vorgestellt. Dabei sind wir soweit gekommen, dass wir den kompletten Inhalt einer XML-Datei im Direktbereich des VBA-Editors ausgegeben haben. Das kann nat&uuml;rlich nicht alles sein: Die Daten sollen ja in der Regel in den Tabellen der Datenbank landen. Den Ereignisprozeduren, welche das XML-Dokument sequenziell durchlaufen, m&uuml;ssen wir dabei nat&uuml;rlich noch die eine oder andere zus&auml;tzliche Anweisung hinzuf&uuml;gen, damit die Daten an der gew&uuml;nschten Stelle gespeichert werden.<\/b><\/p>\n<p>Das sequenzielle Einlesen einer XML-Datei und die Ausgabe der gefundenen Daten ist bereits ein guter Startpunkt. Aber wie machen wir dann weiter, um die Daten, die ja meist in mehreren Datens&auml;tzen landen sollen, in eine entsprechende Tabelle zu schreiben<\/p>\n<p>Mit dem DOM-Parser war das relativ einfach: Man hat beispielsweise alle <b>Kunde<\/b>-Elemente mit der <b>SelectNodes<\/b>-Methode identifiziert und diese dann durchlaufen, wobei f&uuml;r jedes Element ein neuer Datensatz angelegt wurde. Die einzelnen Daten konnte man dann einfach &uuml;ber die entsprechenden Objekte einlesen.<\/p>\n<p>Beim SAX-Parser ist dies v&ouml;llig anders: Hier kann man nicht mal eben alle Kunde-Elemente durchlaufen. Genau genommen kann der SAX-Parser nur entweder alle Elemente durchlaufen &euro;&#8220; oder gar keines.<\/p>\n<p>Dabei werden dann immer die gleichen Ereignisprozeduren ausgel&ouml;st, in denen wir lediglich mit den per Parameter &uuml;bermittelten Daten arbeiten k&ouml;nnen.<\/p>\n<p>Genau genommen liefert jede Ereignisprozedur f&uuml;r sich noch nicht einmal ausreichend Informationen, um die Inhalte der Elemente den richtigen Elementen zuordnen zu k&ouml;nnen. Darum m&uuml;ssen wir uns selbst k&uuml;mmern.<\/p>\n<p><b>Beispieldaten<\/b><\/p>\n<p>Im ersten Beispiel wollen wir die Daten aus der XML-Datei <b>Kunden.xml <\/b>einlesen (s. Listing 1).<\/p>\n<pre>&lt;xml version=\"1.0\" encoding=\"utf-8\"&gt;\r\n&lt;Kunden xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" \r\n                                      xmlns:xsd=\"http:\/\/www.w3.org\/2001\/XMLSchema\"&gt;\r\n   &lt;Kunde KundeID=\"123\"&gt;\r\n     &lt;Vorname&gt;Andr&eacute;&lt;\/Vorname&gt;\r\n     &lt;Nachname&gt;Minhorst&lt;\/Nachname&gt;\r\n   &lt;\/Kunde&gt;\r\n   &lt;Kunde KundeID=\"124\"&gt;\r\n     &lt;Vorname&gt;Hermann&lt;\/Vorname&gt;\r\n     &lt;Nachname&gt;M&uuml;ller&lt;\/Nachname&gt;\r\n   &lt;\/Kunde&gt;\r\n   &lt;Kunde KundeID=\"125\"&gt;\r\n     &lt;Vorname&gt;Klaus&lt;\/Vorname&gt;\r\n     &lt;Nachname&gt;Meier&lt;\/Nachname&gt;\r\n   &lt;\/Kunde&gt;\r\n&lt;\/Kunden&gt;<\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Beispiel eines XML-Dokuments mit Kundendaten<\/span><\/b><\/p>\n<p>Diese sollen in der Tabelle <b>tblKunden <\/b>landen, die lediglich ein Prim&auml;rschl&uuml;sselfeld namens <b>KundeID <\/b>sowie zwei Textfelder namens <b>Vorname <\/b>und <b>Nachname <\/b>enth&auml;lt (s. Bild 1).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2015_01\/pic_970_001.png\" alt=\"Die Tabelle tblKunden\" width=\"450\" height=\"327,7878\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Die Tabelle tblKunden<\/span><\/b><\/p>\n<p>Wir verwenden an dieser Stelle das bereits im Beitrag <b>XML-Dokumente mit SAX parsen <\/b>verwendete Formular namens <b>frmSAX<\/b>, um den Einlesevorgang zu starten. Dieses Formular bietet die M&ouml;glichkeit, eine Datei auszuw&auml;hlen und per Mausklick den Einlesevorgang auszul&ouml;sen (s. Bild 2).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2015_01\/pic_970_002.png\" alt=\"Formular zum Starten des Einlesevorgangs\" width=\"450\" height=\"148,6535\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Formular zum Starten des Einlesevorgangs<\/span><\/b><\/p>\n<p>Die Schaltfl&auml;che <b>cmdEinlesen<\/b> l&ouml;st die Prozedur aus Listing 2 aus. Diese verwendet die Klasse <b>clsSAX<\/b>, welche die Ereignisprozeduren der Schnittstelle <b>MSXML2.IVBSAXContentHandler <\/b>implementiert. In diese Ereignisprozeduren schreiben wir nachfolgend den Code, der zum Einlesen der Daten aus der XML-Datei <b>Kunden.xml <\/b>ben&ouml;tigt wird.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdEinlesen_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>objReader<span style=\"color:blue;\"> As <\/span>SAXXMLReader60\r\n     <span style=\"color:blue;\">Dim <\/span>objSax<span style=\"color:blue;\"> As <\/span>clsSAX\r\n     <span style=\"color:blue;\">Set<\/span> objReader = <span style=\"color:blue;\">New<\/span> SAXXMLReader60\r\n     <span style=\"color:blue;\">Set<\/span> objSax = <span style=\"color:blue;\">New<\/span> clsSAX\r\n     <span style=\"color:blue;\">Set<\/span> objReader.contentHandler = objSax\r\n     objReader.parseURL Me!txtDatei\r\n     <span style=\"color:blue;\">Set<\/span> objReader = Nothing\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Start des Einlesevorgangs<\/span><\/b><\/p>\n<p>Dazu ben&ouml;tigen wir prinzipiell die folgenden Ereignisprozeduren:<\/p>\n<ul>\n<li><b>IVBSAXContentHandler_startDocument()<\/b>: Wird beim Start des Einlesevorgangs ausgel&ouml;st. Hier bringen wir Anweisungen unter, die das Database-Objekt und das Recordset zum Hinzuf&uuml;gen der Daten vorbereiten.<\/li>\n<li><b>IVBSAX-Content-Handler_start-Ele-ment(strName-spaceURI As String, strLocalName As String, strQName As String, ByVal oAttributes As MSXML2.IVBSAXAttributes)<\/b>: Diese Prozedur wird f&uuml;r jedes Element ausgel&ouml;st. Hier pr&uuml;fen wir per <b>Select Case<\/b>-Anweisung, welches Element gerade durchlaufen wird. Beim <b>Kunde<\/b>-Element etwa m&uuml;ssen wir einen neuen Datensatz im Recordset anlegen. In unserem Beispiel m&uuml;ssen wir hier auch das Attribut <b>KundeID <\/b>auslesen und den Wert gleich in das Feld <b>KundeID <\/b>des neuen Datensatzes eintragen. Bei den Elementen <b>Vorname <\/b>oder <b>Nachname <\/b>m&uuml;ssen wir uns merken, dass nun wohl Inhalte f&uuml;r diese Elemente &uuml;ber die Ereignisprozedur <b>IVBSAXContentHandler_characters <\/b>geliefert werden.<\/li>\n<li><b>IVBSAXContentHandler_characters(strChars As String)<\/b>: Hier werden die eigentlichen Inhalte der Elemente geliefert. Zusammen mit dem zuvor gemerkten Elementnamen k&ouml;nnen wir diese nun in die entsprechenden Felder eintragen.<\/li>\n<li><b>IVBSAXContentHandler_endElement(strNamespaceURI As String, strLocalName As String, strQName As String)<\/b>: Auch beim Ende eines Elements (etwa <b><\/Kunde><\/b>) m&uuml;ssen wir per <b>Select Case <\/b>verschiedene F&auml;lle untersuchen. Beim Element <b>Vorname <\/b>oder <b>Nachname <\/b>brauchen wir nichts zu tun. Beim Element Kunde m&uuml;ssen wir hingegen den Datensatz speichern, den wir zuvor mit den Werten f&uuml;r die Felder <b>KundeID<\/b>, <b>Vorname <\/b>und <b>Nachname <\/b>gef&uuml;llt haben.<\/li>\n<li><b>IVBSAXContentHandler_endDocument()<\/b>: Dies bedeutet das Ende des Einlesevorgangs. <b>Recordset<\/b>&#8211; und <b>Database<\/b>-Objekt k&ouml;nnen nun geschlossen beziehungsweise die Objektvariablen geleert werden.<\/li>\n<\/ul>\n<p>Damit begeben wir uns an die Arbeit. Beachten Sie, dass Sie &euro;&#8220; auch wenn wir nur einige der verf&uuml;gbaren Ereignisse verwenden &euro;&#8220; alle Ereignisse der Schnittstelle implementieren m&uuml;ssen.<\/p>\n<p><b>Deklarationen<\/b><\/p>\n<p>Zun&auml;chst ben&ouml;tigen wir einige Deklarationen f&uuml;r Objekte, die von mehreren der Ereignisprozeduren verwendet werden. Da w&auml;re zum Beispiel das <b>Database<\/b>-Objekt, das in der Prozedur <b>IVBSAXContentHandler_startDocument <\/b>gef&uuml;llt und in <b>IVBSAXContentHandler_endDocument <\/b>wieder geleert werden soll. Daher landet die Deklaration im Kopf des Klassenmoduls <b>clsSAX<\/b>:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database<\/pre>\n<p>Desweiteren ben&ouml;tigen wir ein Recordset, das wir in <b>startDocument <\/b>erstellen, in <b>startElement <\/b>mit einem neuen Datensatz f&uuml;llen, dessen Felder in <b>IVBSAXContentHandler_characters <\/b>ihre Werte erhalten, das in <b>IVBSAXContentHandler_endElement <\/b>gespeichert und das in <b>IVBSAXContentHandler_endDocument <\/b>geschlossen wird:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>rstKunden<span style=\"color:blue;\"> As <\/span>DAO.Recordset<\/pre>\n<p>Schlie&szlig;lich fehlt noch eine Variable, mit der wir uns merken k&ouml;nnen, welches Element gerade in <b>IVBSAXContentHandler_startElement <\/b>durchlaufen wurde:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>strFeld<span style=\"color:blue;\"> As String<\/span><\/pre>\n<p><b>Start des Dokuments<\/b><\/p>\n<p>Das Ereignis <b>IVBSAXContentHandler_startDocument <\/b>implementieren wir wie in Listing 3. Diese Prozedur f&uuml;llt zun&auml;chst die Variable <b>db<\/b> mit einem Verweis auf die aktuelle Datenbank. Die <b>Recordset<\/b>-Variable <b>rstKunden <\/b>f&uuml;llen wir mit der <b>OpenRecordset<\/b>-Methode, die ein Recordset mit allen Datens&auml;tzen der Tabelle <b>tblKunden <\/b>zur&uuml;ckliefert. Dies alles fassen wir in eine rudiment&auml;re Fehlerbehandlung ein, damit wir Fehler gleich an Ort und Stelle untersuchen k&ouml;nnen.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>IVBSAXContentHandler_startDocument()\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> rstKunden = db.OpenRecordset(\"SELECT * FROM tblKunden\", dbOpenDynaset)\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> Err.Number = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> Err.Number & \" \" & Err.Description\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Start des Dokuments<\/span><\/b><\/p>\n<p><b>Start eines Elements<\/b><\/p>\n<p>Danach wird als n&auml;chste f&uuml;r uns interessante Ereignisprozedur <b>IVBSAXContentHandler_startElement <\/b>ausgel&ouml;st (s. Listing 4).<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>IVBSAXContentHandler_startElement(strNamespaceURI<span style=\"color:blue;\"> As String<\/span>, _\r\n         strLocalName<span style=\"color:blue;\"> As String<\/span>, strQName<span style=\"color:blue;\"> As String<\/span>, _\r\n         ByVal oAttributes<span style=\"color:blue;\"> As <\/span>MSXML2.IVBSAXAttributes)\r\n     <span style=\"color:blue;\">Dim <\/span>lngKundeID<span style=\"color:blue;\"> As Long<\/span>\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     Select Case strLocalName\r\n         <span style=\"color:blue;\">Case <\/span>\"Kunde\"\r\n             lngKundeID = oAttributes.getValueFromName(\"\", \"KundeID\")\r\n             db.Execute \"DELETE FROM tblKunden WHERE KundeID = \" & lngKundeID, _\r\n                 dbFailOnError\r\n             rstKunden.Add<span style=\"color:blue;\">New<\/span>\r\n             rstKunden!KundeID = lngKundeID\r\n             strFeld = \"\"\r\n         <span style=\"color:blue;\">Case <\/span>\"Vorname\", \"Nachname\"\r\n             strFeld = strLocalName\r\n         <span style=\"color:blue;\">Case Else<\/span>\r\n             strFeld = \"\"\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> Err.Number = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> Err.Number & \" \" & Err.Description\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Start eines Elements<\/span><\/b><\/p>\n<p>Hier pr&uuml;fen wir zun&auml;chst in einer <b>Select Case<\/b>-Bedingung, welches Element an der Reihe ist. Als Erstes wird hier das Element <b>Kunden <\/b>erscheinen, um das wir uns aber an dieser Stelle nicht zu k&uuml;mmern brauchen &euro;&#8220; dies wird erst interessant, wenn ein XML-Dokument mehrerer solcher Hauptelemente enth&auml;lt (wie Kunden, Artikel, Bestellungen et cetera).<\/p>\n<p>Danach folgt das Element <b>Kunde <\/b>und wir beginnen, den ersten Kunden in der Tabelle <b>tblKunden <\/b>einzuf&uuml;gen.<\/p>\n<p>Der entsprechende Zweig der <b>Select Case<\/b>-Bedingung ermittelt zun&auml;chst den Wert des Attributs <b>KundeID <\/b>&euro;&#8220; das ja in diesem Element enthalten ist:<\/p>\n<pre>  &lt;Kunde KundeID=\"123\"&gt;<\/pre>\n<p>Dazu verwendet es die Funktion <b>getValue-FromName <\/b>des mitgelieferten Parameters <b>oAttributes <\/b>und &uuml;bergibt den Namen des Attributs (hier <b>KundeID<\/b>) als zweiten Parameter. Wir wollen Kundendatens&auml;tze, deren <b>KundeID<\/b> bereits vergeben ist, einfach l&ouml;schen und neu f&uuml;llen. Je nach Anforderungen werden Sie diesen Sachverhalt anders programmieren wollen. Dann legt die Prozedur mit der <b>AddNew<\/b>-Methode einen neuen Datensatz in der Tabelle <b>tblKunden <\/b>an. Da wir den Prim&auml;rschl&uuml;sselwert bereits kennen, f&uuml;gen wir diesen f&uuml;r das Feld <b>KundeID<\/b> ein (dieses darf zu diesem Zweck nicht als Autowert definiert sein).<\/p>\n<p>Au&szlig;erdem stellen wir die Variable <b>strFeld <\/b>auf eine leere Zeichenkette ein.<\/p>\n<p>Sp&auml;ter wird diese Prozedur f&uuml;r die Elemente <b>Vorname<\/b> und <b>Nachname <\/b>ausgel&ouml;st. In diesem Fall m&uuml;ssen wir nat&uuml;rlich keinen neuen Datensatz anlegen.<\/p>\n<p>Wir k&ouml;nnen auch die Werte noch nicht eintragen, da diese ja erst in der Ereignisprozedur <b>IVBSAXContentHandler_characters <\/b>&uuml;bermittelt werden.<\/p>\n<p>Aber damit wir sp&auml;ter beim Ausl&ouml;sen der Prozedur <b>IVBSAXContentHandler_characters <\/b>wissen, zu welchem Feld die enthaltenen Werte geh&ouml;ren, merken wir uns nun mithilfe der Variablen <b>strFeld <\/b>den Namen des Elements &euro;&#8220; also entweder <b>Vorname <\/b>oder <b>Nachname<\/b>.<\/p>\n<p><b>Inhalt eines Elements einlesen<\/b><\/p>\n<p>Damit geht es gleich weiter mit der Ereignisprozedur <b>IVBSAXContentHandler_characters<\/b> (s. Listing 5). Diese Prozedur erh&auml;lt mit dem Parameter <b>strChars <\/b>den Inhalt des Elements.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>IVBSAXContentHandler_characters(strChars<span style=\"color:blue;\"> As String<\/span>)\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     Select Case strFeld\r\n         <span style=\"color:blue;\">Case <\/span>\"Vorname\"\r\n             rstKunden!Vorname = strChars\r\n         <span style=\"color:blue;\">Case <\/span>\"Nachname\"\r\n             rstKunden!Nachname = strChars\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> Err.Number = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> Err.Number & \" \" & Err.Description\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Einlesen des Wertes eines Elements<\/span><\/b><\/p>\n<p>Dabei kann es sich auch um Zeilenumbr&uuml;che oder Einsch&uuml;be handeln, wenn das aktuelle Element weitere Unterelemente enth&auml;lt.<\/p>\n<p>Angenommen, das XML-Dokument ist an dieser Stelle wie folgt aufgebaut:<\/p>\n<pre>   &lt;Kunde KundeID=\"123\"&gt;\r\n     &lt;Vorname&gt;Andr&eacute;&lt;\/Vorname&gt;<\/pre>\n<p>Dann folgt nach dem Element <b>Kunde <\/b>zuerst ein Aufruf der Prozedur <b>IVBSAXContentHandler_characters<\/b>, bei der <b>strChars <\/b>den Zeilenumbruch von der Zeile <b>&lt;Kunde&#8230; <\/b>zur Zeile <b>&lt;Vorname <\/b>enth&auml;lt.<\/p>\n<p>Dann folgt ein weiterer Aufruf der Prozedur <b>IVBSAXContentHandler_characters<\/b>, welcher mit dem Parameter <b>strChars <\/b>die Einr&uuml;ckung des Textes <b>&lt;Vorname&#8230; <\/b>enth&auml;lt (also etwa einige Leerzeichen oder ein Tabulator-Zeichen).<\/p>\n<p>Wenn Sie ein XML-Dokument verwenden, das um Zeilenumbr&uuml;che und Einsch&uuml;be bereinigt ist, entfallen diese zahlreichen Aufrufe der Ereignisporzedur <b>IVBSAXContentHandler_characters<\/b> jedoch &euro;&#8220; dies d&uuml;rfte sich positiv auf die Performance auswirken.<\/p>\n<p>Solche Zeichen ignorieren wir jedoch, indem wir in einer <b>Select Case<\/b>-Bedingung den Wert der Variablen <b>strFeld <\/b>pr&uuml;fen. Dabei wird die Prozedur nur t&auml;tig, wenn <b>strFeld <\/b>entweder den Wert <b>Vorname <\/b>oder <b>Nachname <\/b>enth&auml;lt. In diesem Fall f&uuml;llt die Prozedur das jeweilige Feld des Recordsets <b>rstKunden <\/b>mit dem per <b>strChars <\/b>&uuml;bergebenen Wert.<\/p>\n<p><b>Ende eines Elements<\/b><\/p>\n<p>Die Ereignisprozedur <b>IVBSAXContentHandler_endElement <\/b>wird jeweils ausgel&ouml;st, wenn der SAX-Parser auf ein Element mit <b>&lt;\/&#8230; <\/b>st&ouml;&szlig;t (s. Listing 6). In unserem Beispiel geschieht dies zum ersten Mal mit dem Element <b>&lt;\/Vorname&gt;<\/b>, dann mit <b>&lt;\/Nachname&gt;<\/b>. Hier geschieht nichts, da die Prozedur in einer <b>Select Case<\/b>-Bedingung lediglich den Fall des Elements <b>Kunde <\/b>ber&uuml;cksichtigt.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>IVBSAXContentHandler_endElement(strNamespaceURI<span style=\"color:blue;\"> As String<\/span>, _\r\n         strLocalName<span style=\"color:blue;\"> As String<\/span>, strQName<span style=\"color:blue;\"> As String<\/span>)\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     Select Case strLocalName\r\n         <span style=\"color:blue;\">Case <\/span>\"Kunde\"\r\n             rstKunden.Update\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n     strFeld = \"\"\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> Err.Number = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> Err.Number & \" \" & Err.Description\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 6: Bearbeitung des Ende-Tags eines Elements<\/span><\/b><\/p>\n<p>Dies bedeutet, dass das komplette <b>Kunde<\/b>-Element samt enthaltenen Feldern abgearbeitet wurde und der Datensatz gespeichert werden kann. Dies erledigt die Prozedur mit der <b>Update<\/b>-Methode des <b>Recordset<\/b>-Objekts.<\/p>\n<p><b>Ende des Dokuments<\/b><\/p>\n<p>Nachdem alle Elemente eingelesen wurden, l&ouml;st der SAX-Parser schlie&szlig;lich noch die Ereignisprozedur <b>IVBSAXContentHandler_endDocument <\/b>aus (s. Listing 7). Hier brauchen wir nur noch das ge&ouml;ffnete Recordset zu schlie&szlig;en und die Variablen <b>db <\/b>und <b>rstKunden <\/b>zu leeren.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>IVBSAXContentHandler_endDocument()\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     rstKunden.Close\r\n     <span style=\"color:blue;\">Set<\/span> rstKunden = Nothing\r\n     <span style=\"color:blue;\">Set<\/span> db = Nothing\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> Err.Number = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> Err.Number & \" \" & Err.Description\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 7: Abschluss des Einlesevorgangs<\/span><\/b><\/p>\n<p>Ein Blick in die Tabelle <b>tblKunden <\/b>zeigt, dass die Daten erfolgreich gespeichert wurden (s. Bild 3).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2015_01\/pic_970_003.png\" alt=\"Die Tabelle tblKunden mit einigen Beispieldaten\" width=\"400\" height=\"213,4615\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Die Tabelle tblKunden mit einigen Beispieldaten<\/span><\/b><\/p>\n<p><b>Speichern in eine Tabelle mit Autowert-Feld<\/b><\/p>\n<p>Nun hat man nicht immer die Gelegenheit, die Zieltabelle selbst zu definieren. W&auml;hrend wir hier also der Einfachheit halber den Prim&auml;rschl&uuml;sselwert nicht als Autowert definiert haben, ist dies normalerweise nicht der Fall.<\/p>\n<p>Wie aber bekommen wir den Prim&auml;rschl&uuml;sselwert, hier aus dem Attribut <b>KundeID <\/b>der <b>Kunde<\/b>-Elemente, in das Prim&auml;rschl&uuml;sselfeld Legen wir doch als Erstes eine Kopie der Tabelle <b>tblKunden <\/b>unter dem Namen <b>tblKundenMitAutowert <\/b>an und &auml;ndern dort den Felddatentyp des Feldes <b>KundeID <\/b>auf Autowert (s. Bild 4).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2015_01\/pic_970_004.png\" alt=\"Die Tabelle tblKunden mit Autowert als Prim&auml;rschl&uuml;ssel\" width=\"400\" height=\"249,453\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Die Tabelle tblKunden mit Autowert als Prim&auml;rschl&uuml;ssel<\/span><\/b><\/p>\n<p>Au&szlig;erdem f&uuml;gen wir dem Formular <b>frmSAX <\/b>eine weitere Schaltfl&auml;che namens <b>cmdEinlesenMitAutowert <\/b>hinzu. Diese l&ouml;st die Prozedur aus Listing 8 aus. Der Unterschied zu der Prozedur der anderen Schaltfl&auml;che ist, dass wir hier die neu erstellte Klasse <b>clsSAXMitAutowert <\/b>referenzieren. Schlie&szlig;lich kopieren wir die Klasse <b>clsSAX <\/b>in eine neue Klasse namens <b>clsSAXMitAutowert<\/b>. <\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdEinlesenMitAutowert_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>objReader<span style=\"color:blue;\"> As <\/span>SAXXMLReader60\r\n     <span style=\"color:blue;\">Dim <\/span>objSax<span style=\"color:blue;\"> As <\/span>clsSAXMitAutowert\r\n     <span style=\"color:blue;\">Set<\/span> objReader = <span style=\"color:blue;\">New<\/span> SAXXMLReader60\r\n     <span style=\"color:blue;\">Set<\/span> objSax = <span style=\"color:blue;\">New<\/span> clsSAXMitAutowert\r\n     <span style=\"color:blue;\">Set<\/span> objReader.contentHandler = objSax\r\n     objReader.parseURL Me!txtDatei\r\n     <span style=\"color:blue;\">Set<\/span> objReader = Nothing\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><!--30percent--><\/p>\n<p><b><span style=\"color:darkgrey;\">Listing 8: Einlesen der gleichen Datei, diesmal in eine Tabelle mit Autowert-Feld<\/span><\/b><\/p>\n<p>Danach wollen wir uns ansehen, ob wir die Tabelle mit dem Autowert im Prim&auml;rschl&uuml;sselfeld nicht einfach genauso f&uuml;llen k&ouml;nnen wie im vorherigen Beispiel (s. Listing 9). Und siehe da: Es klappt ohne Probleme! Sie m&uuml;ssen bei einem Autowert-Feld also nicht unbedingt den Autowert nutzen, sondern k&ouml;nnen auch neue Datens&auml;tze mit eigenem Prim&auml;rschl&uuml;sselwert einf&uuml;gen.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>IVBSAXContentHandler_startDocument()\r\n     ...\r\n     <span style=\"color:blue;\">Set<\/span> rstKunden = db.OpenRecordset(\"SELECT * FROM tblKundenMitAutowert\", dbOpenDynaset)\r\n     ...\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>IVBSAXContentHandler_startElement(strNamespaceURI<span style=\"color:blue;\"> As String<\/span>, strLocalName<span style=\"color:blue;\"> As String<\/span>, strQName<span style=\"color:blue;\"> As String<\/span>, _\r\n     ByVal oAttributes<span style=\"color:blue;\"> As <\/span>MSXML2.IVBSAXAttributes)\r\n     ...\r\n             db.Execute \"DELETE FROM tblKundenMitAutowert WHERE KundeID = \" & lngKundeID, dbFailOnError\r\n     ...\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 9: &auml;nderungen in der Klasse clsSAXMitAutowert, um die Daten in eine andere Tabelle einzulesen<\/span><\/b><\/p>\n<p><b>Einlesen von XML-Dateien mit Lookup-Daten<\/b><\/p>\n<p>Im folgenden Beispiel sehen wir uns an, wie wir mit dem SAX-Parser arbeiten, um Daten aus einem XML-Dokument in Tabellen mit Lookup-Tabelle zu importieren. Dazu haben wir die Beispieldatei um das Element <b>Anrede <\/b>erweitert, das zum Beispiel die Werte <b>Herr <\/b>oder <b>Frau <\/b>aufnimmt. Das Dokument haben wir unter dem Namen <b>KundeMitAnrede.xml <\/b>gespeichert (s. Listing 10).<\/p>\n<pre>&lt;xml version=\"1.0\" encoding=\"utf-8\"&gt;\r\n&lt;Kunden xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" \r\n                                      xmlns:xsd=\"http:\/\/www.w3.org\/2001\/XMLSchema\"&gt;\r\n   &lt;Kunde KundeID=\"123\"&gt;\r\n     &lt;Anrede&gt;Herr&lt;\/Anrede&gt;\r\n     &lt;Vorname&gt;Andr&eacute;&lt;\/Vorname&gt;\r\n     &lt;Nachname&gt;Minhorst&lt;\/Nachname&gt;\r\n   &lt;\/Kunde&gt;\r\n   &lt;Kunde KundeID=\"124\"&gt;\r\n     &lt;Anrede&gt;Herr&lt;\/Anrede&gt;\r\n     &lt;Vorname&gt;Hermann&lt;\/Vorname&gt;\r\n     &lt;Nachname&gt;M&uuml;ller&lt;\/Nachname&gt;\r\n   &lt;\/Kunde&gt;\r\n   &lt;Kunde KundeID=\"125\"&gt;\r\n     &lt;Anrede&gt;Frau&lt;\/Anrede&gt;\r\n     &lt;Vorname&gt;Claudia&lt;\/Vorname&gt;\r\n     &lt;Nachname&gt;Meier&lt;\/Nachname&gt;\r\n   &lt;\/Kunde&gt;\r\n&lt;\/Kunden&gt;<\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 10: Die Anrede soll in einem Fremdschl&uuml;sselfeld landen.<\/span><\/b><\/p>\n<p>Die Zieltabellen sehen wie in Bild 5 aus. Die Tabelle <b>tblKundenMitAnrede <\/b>ist dabei &uuml;ber das Fremdschl&uuml;sselfeld <b>AnredeID <\/b>mit dem gleichnamigen Prim&auml;rschl&uuml;sselfeld der Tabelle <b>tblAnreden <\/b>verkn&uuml;pft. Ziel ist es nun, eine neue Klasse <b>clsSAXMitLookupTabelle <\/b>zu programmieren, welche die <b>Anreden <\/b>aus dem Element <b>Anrede <\/b>direkt in die Tabelle eintr&auml;gt und den neuen Prim&auml;rschl&uuml;sselwert nutzt. Dies soll nat&uuml;rlich nur geschehen, wenn der Wert noch nicht in der Tabelle <b>tblAnreden <\/b>enthalten ist. Anderenfalls soll die Prozedur einfach den Prim&auml;rschl&uuml;sselwert des entsprechenden Datensatzes der Tabelle <b>tblAnreden <\/b>ermitteln und in das Fremdschl&uuml;sselfeld der Tabelle <b>tblKundenMitAnrede <\/b>eintragen.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2015_01\/pic_970_005.png\" alt=\"Kundentabelle mit Anreden in einer Lookup-Tabelle\" width=\"400\" height=\"155,6026\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Kundentabelle mit Anreden in einer Lookup-Tabelle<\/span><\/b><\/p>\n<p>Um dies zu erreichen, ben&ouml;tigen wir zwei &auml;nderungen in den Prozeduren <b>IVBSAXContentHandler_startElement <\/b>und <b>IVBSAXContentHandler_characters<\/b>. Die &auml;nderungen finden Sie in Listing 11 in fetter Schrift.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>IVBSAXContentHandler_startElement(strNamespaceURI<span style=\"color:blue;\"> As String<\/span>, strLocalName<span style=\"color:blue;\"> As String<\/span>, strQName<span style=\"color:blue;\"> As String<\/span>, _\r\n          ByVal oAttributes<span style=\"color:blue;\"> As <\/span>MSXML2.IVBSAXAttributes)\r\n     ...\r\n         <span style=\"color:blue;\">Case <\/span>\"Vorname\", \"Nachname\", \"Anrede\"\r\n             strFeld = strLocalName\r\n     ...\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>IVBSAXContentHandler_characters(strChars<span style=\"color:blue;\"> As String<\/span>)\r\n     ...\r\n     Select Case strFeld\r\n         ...\r\n         <span style=\"color:blue;\">Case <\/span>\"Anrede\"\r\n             lngAnredeID = Nz(DLookup(\"AnredeID\", \"tblAnreden\", \"Anrede = ''\" & strChars & \"''\"), 0)\r\n             <span style=\"color:blue;\">If <\/span>lngAnredeID = 0<span style=\"color:blue;\"> Then<\/span>\r\n                 db.Execute \"INSERT INTO tblAnreden(Anrede) VALUES(''\" & strChars & \"'')\", dbFailOnError\r\n                 lngAnredeID = db.OpenRecordset(\"SELECT @@IDENTITY\").Fields(0)\r\n             <span style=\"color:blue;\">End If<\/span>\r\n             rstKunden!AnredeID = lngAnredeID\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n     ...\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 11: &auml;nderungen, um den Inhalt eines Elements in einem Lookup-Feld abzulegen<\/span><\/b><\/p>\n<p>Zun&auml;chst m&uuml;ssen wir beim Start des Elements den <b>Case<\/b>-Zweig mit dem Vornamen und dem Nachnamen um die <b>Anrede <\/b>erweitern, damit der Wert <b>Anrede <\/b>in der Variablen <b>strFeld <\/b>gespeichert wird.<\/p>\n<p>Au&szlig;erdem m&uuml;ssen wir in der Prozedur <b>IVBSAXContentHandler_characters <\/b>einen <b>Case<\/b>-Zweig hinzuf&uuml;gen. Dieser behandelt eben den Fall, dass <b>strFeld <\/b>den Wert <b>Anrede <\/b>enth&auml;lt. Dann soll die Prozedur zun&auml;chst versuchen, den Prim&auml;rschl&uuml;sselwert des Datensatzes der Tabelle <b>tblAnreden <\/b>zu ermitteln, der den mit <b>strChars <\/b>gelieferten Wert im Feld <b>Anrede <\/b>enth&auml;lt. Ist ein solcher Datensatz noch nicht vorhanden, enth&auml;lt <b>lngAnredeID <\/b>danach den Wert <b>0<\/b>, sonst den entsprechenden Prim&auml;rschl&uuml;sselwert. Ist <b>lngAnredeID <\/b>gleich <b>0<\/b>, muss die Anrede erst noch in der Tabelle <b>tblAnreden <\/b>angelegt werden. Dies erledigt die erste Anweisung innerhalb der folgenden <b>If&#8230;Then<\/b>-Bedingung. Nachdem dies erledigt ist, ermittelt die Prozedur mit der Abfrage <b>SELECT @@IDENTITY <\/b>den Wert des Prim&auml;rschl&uuml;sselfeldes des neuen Datensatzes und speichert diesen in der Variablen <b>lngAnredeID<\/b>. Diesen Wert tr&auml;gt die Prozedur dann f&uuml;r das Feld <b>AnredeID <\/b>des soeben neu angelegten Datensatzes ein.<\/p>\n<p><b>Verschachtelte Daten einlesen<\/b><\/p>\n<p>Gelegentlich werden Informationen in XML-Dokumenten nochmals in weiteren Elementen verschachtelt, um diese besser strukturieren zu k&ouml;nnen. Ein Beispiel zeigt das XML-Dokument aus Listing 12, das die Stra&szlig;e, die PLZ und den Ort der Lieferadresse und der Rechnungsadresse in zwei entsprechend bezeichneten Unterelementen speichert.<\/p>\n<pre>&lt;xml version=\"1.0\" encoding=\"utf-8\"&gt;\r\n&lt;Kunden xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" \r\n                                      xmlns:xsd=\"http:\/\/www.w3.org\/2001\/XMLSchema\"&gt;\r\n   &lt;Kunde KundeID=\"123\"&gt;\r\n     &lt;Anrede&gt;Herr&lt;\/Anrede&gt;\r\n     &lt;Vorname&gt;Andr&eacute;&lt;\/Vorname&gt;\r\n     &lt;Nachname&gt;Minhorst&lt;\/Nachname&gt;\r\n     &lt;Lieferadresse&gt;\r\n       &lt;Strasse&gt;Borkhofer Str. 17&lt;\/Strasse&gt;\r\n       &lt;PLZ&gt;47137&lt;\/PLZ&gt;\r\n       &lt;Ort&gt;Duisburg&lt;\/Ort&gt;\r\n     &lt;\/Lieferadresse&gt;\r\n    &lt;Rechnungsadresse&gt;\r\n       &lt;Strasse&gt;Postfach 12345&lt;\/Strasse&gt;\r\n       &lt;PLZ&gt;47137&lt;\/PLZ&gt;\r\n       &lt;Ort&gt;Duisburg&lt;\/Ort&gt;\r\n     &lt;\/Rechnungsadresse&gt;\r\n   &lt;\/Kunde&gt;\r\n   ...\r\n&lt;\/Kunden&gt;<\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 12: XML-Dokument mit verschachtelten Daten<\/span><\/b><\/p>\n<p>Nat&uuml;rlich k&ouml;nnen wir dies auch unter Access &auml;hnlich abbilden &euro;&#8220; zun&auml;chst wollen wir jedoch die &uuml;blichen Felder wie <b>LieferStrasse<\/b>, <b>LieferPLZ <\/b>und <b>LieferOrt <\/b>sowie <b>RechnungStrasse<\/b>, <b>RechnungPLZ <\/b>und <b>RechnungOrt <\/b>best&uuml;cken. Die Zieltabelle haben wir dazu wie in Bild 6 gestaltet.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2015_01\/pic_970_006.png\" alt=\"Tabelle mit Rechnungs- und Lieferanschrift\" width=\"500\" height=\"269,8864\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: Tabelle mit Rechnungs- und Lieferanschrift<\/span><\/b><\/p>\n<p>Die entsprechende Version der Klasse <b>clsSAX <\/b>hei&szlig;t in diesem Fall <b>clsSAXAdressen<\/b>, die Schaltfl&auml;che im Formular <b>frmSAX <\/b>hei&szlig;t <b>cmdEinlesenMitAdressen <\/b>und die dadurch aufgerufene Prozedur verwendet nat&uuml;rlich die Klasse <b>clsSAXAdressen <\/b>als <b>contentHandler<\/b>.<\/p>\n<p>Wenn wir nun mit der unver&auml;nderten Klasse die Daten einlesen, schreibt der SAX-Parser nat&uuml;rlich nur die drei Felder <b>AnredeID<\/b>, <b>Vorname <\/b>und <b>Nachname <\/b>in die neue Tabelle <b>tblKundenMitAdresse<\/b>. Immerhin tritt aber auch kein Fehler auf. Um dies zu &auml;ndern, legen wir zun&auml;chst folgende Variable im Kopf des Klassenmoduls <b>clsSAXMitAdressen <\/b>an:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>strAdresstyp<span style=\"color:blue;\"> As String<\/span><\/pre>\n<p>Diese soll sp&auml;ter speichern, ob es sich um eine Lieferadresse (<b>Liefer<\/b>) oder eine Rechnungsadresse handelt (<b>Rechnung<\/b>).<\/p>\n<p>In der Ereignisprozedur <b>IVBSAXContentHandler_startDocument <\/b>legen wir dann fest, welche Tabelle als Zieltabelle dieses Imports dient (<b>tblKundenMitAdressen<\/b>) &euro;&#8220; s. Listing 13.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>IVBSAXContentHandler_startDocument()\r\n     ...\r\n     <span style=\"color:blue;\">Set<\/span> rstKunden = db.OpenRecordset(\"SELECT * FROM tblKundenMitAdressen\", _\r\n          dbOpenDynaset)\r\n     ...\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 13: Einstellen der neuen Zieltabelle<\/span><\/b><\/p>\n<p>Nun kommt der Punkt, wo der SAX-Parser zun&auml;chst die Elemente Lieferadresse beziehungsweise Rechnungsadresse durchl&auml;uft und danach die Felder <b>Strasse<\/b>, <b>PLZ <\/b>und <b>Ort<\/b>.<\/p>\n<p>Wir k&ouml;nnten nun einfach den Case-Zweig in <b>IVBSAXContentHandler_characters <\/b>mit <b>Vorname <\/b>und <b>Nachname <\/b>um <b>Strasse<\/b>, <b>PLZ <\/b>und <b>Ort <\/b>erweitern.<\/p>\n<p>Das w&uuml;rde aber nichts n&uuml;tzen, da wir zu diesem Zeitpunkt ja nicht wissen, ob wir es gerade mit der Liefer- oder Rechnungsadresse zu tun haben.<\/p>\n<p>Also m&uuml;ssen wir zuvor in <b>IVBSAXContentHandler_startElement <\/b>herausfinden, welches das aktuell &uuml;bergeordnete Element von <b>Strasse<\/b>, <b>PLZ <\/b>und <b>Ort <\/b>ist &euro;&#8220; <b>Lieferadresse <\/b>oder <b>Rechnungsadresse<\/b>.<\/p>\n<p>Dazu nutzen wir die weiter oben vorgestellte Variable <b>strAdresstyp<\/b>: In einem weiteren <b>Case<\/b>-Zweig in Listing 14 legen wir n&auml;mlich im Falle des Elements <b>Lieferadresse <\/b>den Wert <b>Liefer <\/b>f&uuml;r die Variable <b>strAdresstyp <\/b>fest, f&uuml;r <b>Rechnungsadresse <\/b>den Wert <b>Rechnung<\/b>.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>IVBSAXContentHandler_startElement(strNamespaceURI<span style=\"color:blue;\"> As String<\/span>, _\r\n         strLocalName<span style=\"color:blue;\"> As String<\/span>, strQName<span style=\"color:blue;\"> As String<\/span>, ByVal oAttributes<span style=\"color:blue;\"> As <\/span>MSXML2._\r\n         IVBSAXAttributes)\r\n     ...\r\n     Select Case strLocalName\r\n         <span style=\"color:blue;\">Case <\/span>\"Kunde\"\r\n             ...\r\n         <span style=\"color:blue;\">Case <\/span>\"Vorname\", \"Nachname\", \"Anrede\", \"Strasse\", \"PLZ\", \"Ort\"\r\n             strFeld = strLocalName\r\n         <span style=\"color:blue;\">Case <\/span>\"Lieferadresse\"\r\n             strAdresstyp = \"Liefer\"\r\n         <span style=\"color:blue;\">Case <\/span>\"Rechnungsadresse\"\r\n             strAdresstyp = \"Rechnung\"\r\n         <span style=\"color:blue;\">Case Else<\/span>\r\n             strFeld = \"\"\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n     ...\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 14: Vorbereitung des Speicherns von Liefer- und Rechnungsdaten<\/span><\/b><\/p>\n<p>In der Prozedur <b>IVBSAXContentHandler_characters <\/b>geschieht in diesen beiden F&auml;llen nichts.<\/p>\n<p>Erst wenn dann eines der Unterelemente <b>Strasse<\/b>, <b>PLZ <\/b>oder <b>Ort <\/b>auftaucht, kommt Leben in die Sache.<\/p>\n<p>Die Prozedur <b>IVBSAXContentHandler_startElement <\/b>speichert genau wie bei <b>Vorname <\/b>oder <b>Nachname <\/b>den jeweiligen Elementnamen in der Variablen <b>strFeld<\/b>.<\/p>\n<p>In <b>IVBSAXContentHandler_characters <\/b>dann gibt es einen neuen <b>Case<\/b>-Zweig, der im Falle der Elemente <b>Strasse<\/b>, <b>PLZ <\/b>und <b>Ort <\/b>angesteuert wird (s. Listing 15). In diesem Fall schreibt die Prozedur den Inhalt von <b>strChars <\/b>in ein Feld, dessen Name sich aus den Inhalten der Variablen <b>strAdresstyp <\/b>und <b>strFeld <\/b>zusammensetzt &euro;&#8220; zum Beispiel <b>Liefer <\/b>und <b>Strasse <\/b>gleich <b>LieferStrasse<\/b>.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>IVBSAXContentHandler_characters(strChars<span style=\"color:blue;\"> As String<\/span>)\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngAnredeID<span style=\"color:blue;\"> As Long<\/span>\r\n     Select Case strFeld\r\n         ...\r\n         <span style=\"color:blue;\">Case <\/span>\"Strasse\", \"PLZ\", \"Ort\"\r\n             rstKunden(strAdresstyp & strFeld) = strChars\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n     ...\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 15: Speichern von Rechnungs- und Lieferadressen<\/span><\/b><\/p>\n<p>Das Ergebnis sieht dann wie in Bild 7 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2015_01\/pic_970_007.png\" alt=\"Tabelle mit Daten in den Feldern f&uuml;r die Liefer- und Rechnungsanschrift\" width=\"700\" height=\"130,694\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: Tabelle mit Daten in den Feldern f&uuml;r die Liefer- und Rechnungsanschrift<\/span><\/b><\/p>\n<p><b>Einlesen von XML-Dateien mit m:n-Daten<\/b><\/p>\n<p>Nun schauen wir uns ein komplett neues Beispiel an, bei dem das XML-Dokument die Daten zum F&uuml;llen zweier in einer m:n-Beziehung stehenden Tabellen enth&auml;lt. Dabei geht es um Fahrzeuge und deren Sonderausstattungen, wie sie in Listing 16 abgebildet sind.<\/p>\n<pre>&lt;xml version=\"1.0\" encoding=\"utf-8\"&gt;\r\n&lt;Fahrzeuge xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" \r\n                                      xmlns:xsd=\"http:\/\/www.w3.org\/2001\/XMLSchema\"&gt;\r\n   &lt;Fahrzeug Fahrgestellnummer=\"12345-12345-12345\"&gt;\r\n     &lt;Fahrzeugbezeichnung&gt;Ford Fiesta&lt;\/Fahrzeugbezeichnung&gt;\r\n     &lt;Ausstattungsmerkmale&gt;\r\n       &lt;Ausstattungsmerkmal&gt;Klimaanlage&lt;\/Ausstattungsmerkmal&gt;\r\n       &lt;Ausstattungsmerkmal&gt;Zentralverriegelung&lt;\/Ausstattungsmerkmal&gt;\r\n     &lt;\/Ausstattungsmerkmale&gt;\r\n   &lt;\/Fahrzeug&gt;\r\n   &lt;Fahrzeug Fahrgestellnummer=\"23456-23456-23456\"&gt;\r\n     &lt;Fahrzeugbezeichnung&gt;Ford Galaxy&lt;\/Fahrzeugbezeichnung&gt;\r\n     &lt;Ausstattungsmerkmale&gt;\r\n       &lt;Ausstattungsmerkmal&gt;Klimaanlage&lt;\/Ausstattungsmerkmal&gt;\r\n       &lt;Ausstattungsmerkmal&gt;Zentralverriegelung&lt;\/Ausstattungsmerkmal&gt;\r\n       &lt;Ausstattungsmerkmal&gt;Elektrische Fensterheber&lt;\/Ausstattungsmerkmal&gt;\r\n       &lt;Ausstattungsmerkmal&gt;Bordcomputer&lt;\/Ausstattungsmerkmal&gt;\r\n     &lt;\/Ausstattungsmerkmale&gt;\r\n   &lt;\/Fahrzeug&gt;\r\n&lt;\/Fahrzeuge&gt;<\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 16: XML-Dokument mit Daten f&uuml;r eine m:n-Beziehung<\/span><\/b><\/p>\n<p>Die drei Tabellen, in welche diese Daten abgef&uuml;llt werden sollen, sehen wie in Bild 8 aus. Die Tabelle <b>tblFahrzeuge <\/b>nimmt das Attribut <b>Fahrgestellnummer <\/b>sowie den Inhalt des Elements <b>Fahrzeugbezeichnung <\/b>auf, die Tabelle <b>tblAusstattungsmerkmale <\/b>die Werte des Elements <b>Ausstattungsmerkmal<\/b>. Nun fehlt nur noch die Information, welche Ausstattungsmerkmale mit welchen Fahrzeugen verkn&uuml;pft sind. Diese landen in der Tabelle <b>tblFahrzeugeAusstattungsmerkmale<\/b>, und zwar in Form der Werte der Prim&auml;rschl&uuml;sselwerte der entsprechenden Datens&auml;tze der Tabellen <b>tblFahrzeuge <\/b>und <b>tblAusstattungsmerkmale<\/b>.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2015_01\/pic_970_008.png\" alt=\"Datenmodell f&uuml;r die per m:n-Beziehung verkn&uuml;pften Tabellen\" width=\"650\" height=\"217,617\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 8: Datenmodell f&uuml;r die per m:n-Beziehung verkn&uuml;pften Tabellen<\/span><\/b><\/p>\n<p>Der Ablauf wird hier so aussehen, dass die Prozedur <b>IVBSAXContentHandler_startElement <\/b>als erstes relevantes Element das Element <b>Fahrzeug <\/b>liefert, worauf zun&auml;chst ein eventuell vorhandener Datensatz mit der Fahrgestellnummer aus dem gleichnamigen Attribut gel&ouml;scht werden soll. Dann legt die Prozedur einen neuen Datensatz im Recordset <b>rstFahrzeuge <\/b>an. Als N&auml;chstes dann folgt das Element <b>Fahrzeugbezeichnung<\/b>. Hier wollen wir uns mit der Variablen <b>strFeld <\/b>den Namen des entsprechenden Elements\/Feldes merken. Im n&auml;chsten Schritt l&ouml;st der SAX-Parser die Prozedur <b>IVBSAXContentHandler_characters <\/b>aus, wo wir, da <b>strFeld <\/b>den Wert <b>Fahrzeugbezeichnung <\/b>enth&auml;lt, wissen, dass der Inhalt des Parameters <b>strChars <\/b>im Feld <b>Fahrzeugbezeichnung <\/b>des soeben neu angelegten Datensatzes landen soll.<\/p>\n<p>Bevor nun die Prozedur <b>IVBSAX-Con-tent-Handler_endElement <\/b>f&uuml;r das Element <b>Fahrzeug <\/b>ausgel&ouml;st wird, folgt allerdings noch das Element <b>Ausstattungsmerkmale <\/b>mit den darin enthaltenen Elementen namens <b>Ausstattungsmerkmal<\/b>. Dort legen wir dann &euro;&#8220; zun&auml;chst theoretisch &euro;&#8220; einen neuen Datensatz in der Tabelle <b>tblAusstattungsmerkmale <\/b>an und f&uuml;gen dann einen Datensatz zur Tabelle <b>tblFahrzeugeAusstattungsmerkmale <\/b>hinzu, wobei die Felder <b>FahrzeugID <\/b>und <b>AusstattungsmerkmalID <\/b>mit den Inhalten der jeweiligen Felder der neuen Datens&auml;tze in den verkn&uuml;pften Tabellen gef&uuml;llt werden sollen.<\/p>\n<p>Hier wird es allerdings interessant: Der Wert des Prim&auml;rschl&uuml;sselfeldes des neuen Datensatzes in der Tabelle <b>tblFahrzeuge <\/b>ist uns ja noch gar nicht bekannt, da dieses Recordset noch nicht mit der <b>Update<\/b>-Methode gespeichert wurde. Dies k&ouml;nnen wir aber eigentlich erst erledigen, wenn wir das Element <b><\/Fahrzeug> <\/b>erreicht haben, was die Prozedur <b>IVBSAXContentHandler_endElement <\/b>mit dem Wert <b>Fahrzeug <\/b>f&uuml;r den Parameter <b>strLocalName <\/b>ausl&ouml;st.<\/p>\n<p>Die einfachste Variante f&uuml;r dieses Problem w&auml;re, festzulegen, dass das Element <b><Fahrzeug> <\/b>nach dem schlie&szlig;enden Element <b><\/Ausstattungsmerkmale> <\/b>keine weiteren Elemente mehr enthalten darf. Da alles Weitere den Aufwand erh&ouml;hen w&uuml;rde, gehen wir an dieser Stelle von einer solchen Situation aus.<\/p>\n<p>In diesem Fall w&uuml;rden wir also im &ouml;ffnenden Element <b><Ausstattungsmerkmale> <\/b>die <b>Update<\/b>-Methode f&uuml;r das auf der Tabelle <b>tblFahrzeuge <\/b>basierende Recordset anwenden.<\/p>\n<p>Schauen wir uns also an, wie der Code f&uuml;r die f&uuml;nf verwendeten Ereignisprozeduren der Schnittstelle <b>IVBSAXContentHandler <\/b>aussieht.<\/p>\n<p>Zun&auml;chst einmal ben&ouml;tigen wir einige modulweit deklarierte Variablen:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n<span style=\"color:blue;\">Dim <\/span>rstFahrzeuge<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n<span style=\"color:blue;\">Dim <\/span>strFeld<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Dim <\/span>lngFahrzeugID<span style=\"color:blue;\"> As Long<\/span>\r\n<span style=\"color:blue;\">Dim <\/span>lngAusstattungsmerkmalID<span style=\"color:blue;\"> As Long<\/span><\/pre>\n<p><b>Start des Dokuments<\/b><\/p>\n<p>Zwei davon, n&auml;mlich die beiden Recordset-Variablen <b>rstFahrzeuge <\/b>und <b>rstAusstattungsmerkmale<\/b>, werden gleich in der Ereignisprozedur <b>IVBSAXContentHandler_startDocument <\/b>mit den entsprechenden Datensatzgruppen aus den Tabellen <b>tblFahrzeuge <\/b>und <b>tblAusstattungsmerkmalen <\/b>gef&uuml;ttert (s. Listing 17).<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>IVBSAXContentHandler_startDocument()\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> rstFahrzeuge = db.OpenRecordset(\"SELECT * FROM tblFahrzeuge\", _\r\n         dbOpenDynaset)\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> Err.Number = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> Err.Number & \" \" & Err.Description\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 17: Initialisieren der Recordsets beim Starten des Dokuments<\/span><\/b><\/p>\n<p><b>Verarbeiten der &ouml;ffnenden Elemente<\/b><\/p>\n<p>In der Prozedur <b>IVBSAXContentHandler_startElement <\/b>k&uuml;mmern wir uns wieder um die &ouml;ffnenden Elemente (s. Listing 18). Hier treffen wir als Erstes auf das Element Fahrzeug. In diesem Fall ermittelt die Prozedur aus dem Attribut <b>Fahrgestellnummer <\/b>des Elements die Fahrgestellnummer. Die folgende Anweisung l&ouml;scht einen eventuell bereits vorhandenen Datensatz mit der gleichen Fahrgestellnummer aus der Tabelle <b>tblFahrzeuge<\/b>. Direkt danach legt sie mit der AddNew-Methode einen neuen Datensatz an und f&uuml;gt die zuvor ermittelte Fahrgestellnummer in das entsprechende Feld ein. Da dieses Element weitere Unterelemente, aber keinen Text enth&auml;lt, stellt die Prozedur <b>strFeld <\/b>auf eine leere Zeichenkette ein.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>IVBSAXContentHandler_startElement(strNamespaceURI<span style=\"color:blue;\"> As String<\/span>, _\r\n         strLocalName<span style=\"color:blue;\"> As String<\/span>, strQName<span style=\"color:blue;\"> As String<\/span>, _\r\n         ByVal oAttributes<span style=\"color:blue;\"> As <\/span>MSXML2.IVBSAXAttributes)\r\n     <span style=\"color:blue;\">Dim <\/span>strFahrgestellnummer<span style=\"color:blue;\"> As String<\/span>\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     Select Case strLocalName\r\n         <span style=\"color:blue;\">Case <\/span>\"Fahrzeug\"\r\n             strFahrgestellnummer = oAttributes.getValueFromName(\"\", _\r\n                 \"Fahrgestellnummer\")\r\n             db.Execute \"DELETE FROM tblFahrzeuge WHERE Fahrgestellnummer = ''\" _\r\n                 & strFahrgestellnummer & \"''\", dbFailOnError\r\n             rstFahrzeuge.Add<span style=\"color:blue;\">New<\/span>\r\n             rstFahrzeuge!Fahrgestellnummer = strFahrgestellnummer\r\n             strFeld = \"\"\r\n         <span style=\"color:blue;\">Case <\/span>\"Fahrzeugbezeichnung\"\r\n             strFeld = strLocalName\r\n         <span style=\"color:blue;\">Case <\/span>\"Ausstattungsmerkmale\"\r\n             lngFahrzeugID = rstFahrzeuge!FahrzeugID\r\n             rstFahrzeuge.Update\r\n         <span style=\"color:blue;\">Case <\/span>\"Ausstattungsmerkmal\"\r\n             strFeld = strLocalName\r\n         <span style=\"color:blue;\">Case Else<\/span>\r\n             strFeld = \"\"\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> Err.Number = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> Err.Number & \" \" & Err.Description\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 18: L&ouml;schen und Neuanlegen von Fahrzeugen in der Tabelle tblFahrzeuge<\/span><\/b><\/p>\n<p>Sollte die Ereignisprozedur mit dem Wert <b>Fahrzeugbezeichnung <\/b>als Elementname ausgel&ouml;st werden, speichert sie den Wert <b>Fahrzeugbezeichnung <\/b>in der Variablen <b>strFeld<\/b>, damit die nachfolgend aufgerufene Prozedur <b>IVBSAXContentHandler_characters <\/b>wei&szlig;, welchem Feld die eingelesenen Inhalte zuzuordnen sind.<\/p>\n<p>Interessant wird es, wenn das Element <b>Ausstattungsmerkmale <\/b>auftaucht. Sie erinnern sich, dass wir gesagt haben, dass zu diesem Zeitpunkt alle anderen Elemente mit Eigenschaften f&uuml;r diesen Datensatz der Tabelle <b>tblFahrzeuge <\/b>bereits abgearbeitet sein sollten.<\/p>\n<p>Also lesen wir nun zun&auml;chst den Wert des Prim&auml;rschl&uuml;sselfeldes <b>FahrzeugID <\/b>in die Variable <b>lngFahrzeugID <\/b>ein und speichern den aktuellen Datensatz mit der <b>Update<\/b>-Methode. Damit haben wir die Voraussetzungen erf&uuml;llt, weiter unten die Kombinationen aus Fahrzeug und Ausstattungsmerkmal in die Tabelle <b>tblFahrzeugeAusstattungsmerkmale <\/b>zu schreiben.<\/p>\n<p>Auf die Elemente des Typs <b>Ausstattungsmerkmal <\/b>bereiten wir uns auch vor, indem wir deren Bezeichnung beim Auftauchen eines solchen mit der Variablen <b>strFeld <\/b>festhalten.<\/p>\n<p><b>Details zu Fahrzeugen und Ausstattungsmerkmalen speichern<\/b><\/p>\n<p>Damit kommen wir zu der Prozedur aus Listing 19. Diese wird beispielsweise f&uuml;r den Inhalt des Elements <b>Fahrzeugbezeichnung <\/b>aufgerufen. In diesem Fall tragen wir den mit <b>strChars <\/b>gelieferten Text einfach in das Feld <b>Fahrzeugbezeichnung <\/b>des Recordsets <b>rstFahrzeuge <\/b>ein.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>IVBSAXContentHandler_characters(strChars<span style=\"color:blue;\"> As String<\/span>)\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     Select Case strFeld\r\n         <span style=\"color:blue;\">Case <\/span>\"Fahrzeugbezeichnung\"\r\n             rstFahrzeuge!Fahrzeugbezeichnung = strChars\r\n         <span style=\"color:blue;\">Case <\/span>\"Ausstattungsmerkmal\"\r\n             lngAusstattungsmerkmalID = Nz(DLookup(\"AusstattungsmerkmalID\", _\r\n                 \"tblAusstattungsmerkmale\", \"Ausstattungsmerkmal = ''\" & strChars _\r\n                 & \"''\"), 0)\r\n             <span style=\"color:blue;\">If <\/span>lngAusstattungsmerkmalID = 0<span style=\"color:blue;\"> Then<\/span>\r\n                 db.Execute \"INSERT INTO tblAusstattungsmerkmale(\" _\r\n                     \"Ausstattungsmerkmal) VALUES(''\" & strChars & \"'')\", dbFailOnError\r\n                 lngAusstattungsmerkmalID = db.OpenRecordset( _\r\n                    \"SELECT @@IDENTITY\").Fields(0)\r\n             <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> Err.Number = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> Err.Number & \" \" & Err.Description\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 19: Einlesen der Fahrzeugbezeichnungen und Sonderausstattungen<\/span><\/b><\/p>\n<p>Falls beim vorherigen Aufruf der Ereignisprozedur <b>IVBSAXContentHandler_startElement <\/b>das Element <b>Ausstattungsmerkmal <\/b>bearbeitet wurde, soll nun ein Ausstattungsmerkmal f&uuml;r das Fahrzeug mit dem in der Variablen <b>lngFahrzeugID <\/b>gespeicherten Prim&auml;rschl&uuml;sselwert angelegt werden.<\/p>\n<p>Dazu versucht die Prozedur zun&auml;chst, den Prim&auml;rschl&uuml;sselwert eines eventuell bereits vorhandenen Ausstattungsmerkmals mit gleicher Bezeichnung zu ermitteln und in der Variablen <b>lngAusstattungsmerkmalID <\/b>zu speichern.<\/p>\n<p>Ist das Ausstattungsmerkmal noch nicht vorhanden, erh&auml;lt <b>lngAusstattungsmerkmalID <\/b>den Wert <b>0<\/b>. In der folgenden <b>If&#8230;Then<\/b>-Bedingung legt die Prozedur dann per <b>INSERT INTO<\/b>-Aktionsabfrage einen entsprechenden neuen Datensatz in der Tabelle <b>tblAusstattungsmerkmale <\/b>an und f&uuml;gt f&uuml;r das Feld Ausstattungsmerkmal den Inhalt des Parameters <b>strChars <\/b>ein.<\/p>\n<p>Den Prim&auml;rschl&uuml;sselwert des neu hinzugef&uuml;gten Datensatzes ermittelt die Prozedur dann per <b>SELECT @@IDENTITY<\/b>-Abfrage.<\/p>\n<p><b>Ausstattungsmerkmale den Fahrzeugen zuordnen<\/b><\/p>\n<p>Fehlt noch der letzte Schritt: Das Eintragen der Zuordnung von <b>Fahrzeugen <\/b>und <b>Ausstattungsmerkmalen <\/b>in die Tabelle <b>tblFahrzeugeAusstattungsmerkmale<\/b>. Dies ist erst m&ouml;glich, wenn die Prim&auml;rschl&uuml;sselwerte der betroffenen Datens&auml;tze aus den beiden Tabellen <b>tblFahrzeuge <\/b>und <b>tblAusstattungsmerkmale <\/b>vorliegen. Dies erledigen wir in der Ereignisprozedur <b>IVBSAXContentHandler_endElement <\/b>aus Listing 20.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>IVBSAXContentHandler_endElement(strNamespaceURI<span style=\"color:blue;\"> As String<\/span>, _\r\n         strLocalName<span style=\"color:blue;\"> As String<\/span>, strQName<span style=\"color:blue;\"> As String<\/span>)\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     Select Case strLocalName\r\n         <span style=\"color:blue;\">Case <\/span>\"Ausstattungsmerkmal\"\r\n             db.Execute \"INSERT INTO tblFahrzeugeAusstattungsmerkmale(\" _\r\n             \"FahrzeugID, AusstattungsmerkmalID) VALUES(\" & lngFahrzeugID & \", \" _\r\n             & lngAusstattungsmerkmalID & \")\", dbFailOnError\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n     strFeld = \"\"\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> Err.Number = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> Err.Number & \" \" & Err.Description\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 20: Abschlie&szlig;ende Arbeiten zu den einzelnen Elementen<\/span><\/b><\/p>\n<p>Die Prozedur f&uuml;gt wiederum per <b>INSERT INTO<\/b>-Aktionsabfrage einen neuen Datensatz zur Tabelle <b>tblFahrzeugeAusstattungsmerkmale <\/b>hinzu, wobei die beiden Werte f&uuml;r die Felder <b>FahrzeugID <\/b>und <b>AusstattungsmerkmalID <\/b>aus den modulweit deklarierten Variablen <b>lngFahrzeugID <\/b>und <b>AusstattungsmerkmalID <\/b>ermittelt werden.<\/p>\n<p><b>Ende des Dokuments Fahrzeuge.xml<\/b><\/p>\n<p>Schlie&szlig;lich folgt noch die Ereignisprozedur <b>IVBSAXContentHandler_endDocument<\/b>, die zum Ende des Dokuments ausgel&ouml;st wird. Sie f&uuml;hrt die &uuml;blichen Abschlussarbeiten wie das Schlie&szlig;en und Leeren der verwendeten Objektvariablen durch (s. Listing 21).<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>IVBSAXContentHandler_endDocument()\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     rstFahrzeuge.Close\r\n     <span style=\"color:blue;\">Set<\/span> rstFahrzeuge = Nothing\r\n     <span style=\"color:blue;\">Set<\/span> db = Nothing\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> Err.Number = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> Err.Number & \" \" & Err.Description\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 21: Aktionen beim Beenden des Dokuments<\/span><\/b><\/p>\n<p><b>Einlesen von Elementen, deren Daten in mehreren G&auml;ngen geliefert werden <\/b><\/p>\n<p>Manchmal h&ouml;ren die eingelesenen Texte scheinbar mittendrin auf. Dies liegt daran, dass der Parser manche Texte in zwei oder mehr Teilen einliest &euro;&#8220; zum Beispiel, wenn sich benannte Zeichen im einzulesenden Text befinden.<\/p>\n<p>Benannte Zeichen sind zum Beispiel die Zeichen <b>&auml; <\/b>f&uuml;r <b>&auml;<\/b>, <b>&ouml; <\/b>f&uuml;r <b>&ouml;<\/b>, <b>&#038;uuml <\/b>f&uuml;r <b>&uuml; <\/b>oder <b>&amp; <\/b>f&uuml;r das Kaufmanns-Und (<b>&#038;<\/b>). Um dies auszuprobieren, haben wir die XML-Datei <b>MehrteiligeTexte.xml <\/b>um ein solches Zeichen angereichert:<\/p>\n<pre>&lt;xml version=\"1.0\" encoding=\"utf-8\"&gt;\r\n&lt;Kunden ...&gt;\r\n   &lt;Kunde KundeID=\"123\"&gt;\r\n     &lt;Bemerkungen&gt;Guter Kunde.&amp;         Pr&auml;sent schicken!&lt;\/Bemerkungen&gt;\r\n     &lt;Vorname&gt;Andr&eacute;&lt;\/Vorname&gt;\r\n     &lt;Nachname&gt;Minhorst&lt;\/Nachname&gt;\r\n   &lt;\/Kunde&gt;\r\n   ...\r\n&lt;\/Kunden&gt;<\/pre>\n<p>Normalerweise w&uuml;rde man davon ausgehen, dass der Text des Elements Bemerkungen genauso in der Datenbank landet, wenn man die Prozeduren zum Einlesen wie in der Klasse <b>clsSAXMehrteiligeTexte <\/b>festlegt und die Tabelle <b>tblKundenMehrteiligeTexte <\/b>um das Feld Bemerkungen erweitert. Das Ergebnis sieht aber schlicht wie in Bild 9 aus &euro;&#8220; und enth&auml;lt nur den letzten Teil des Ausdrucks. Wie nun kommen wir an den Rest des Elements<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2015_01\/pic_970_009.png\" alt=\"Tabelle mit einem Feld, das nur teilweise gef&uuml;llt wurde\" width=\"575\" height=\"295,3267\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 9: Tabelle mit einem Feld, das nur teilweise gef&uuml;llt wurde<\/span><\/b><\/p>\n<p>Der SAX-Parser teilt die Inhalte der Elemente an Stellen auf, die solche Codierungen f&uuml;r Sonderzeichen et cetera enthalten, und ruft die Ereignisprozedur <b>IVBSAXContentHandler_characters <\/b>mehrfach auf: Je einmal f&uuml;r jedes Sonderzeichen und f&uuml;r die davor und dahinter befindlichen Texte. In diesem Fall liefert <b>strChars <\/b>also zuerst den Text <b>Guter Kunde!<\/b>, dann das Kaufmanns-Und <b>(&#038;<\/b>) und schlie&szlig;lich <b>Pr&auml;sent schicken<\/b>.<\/p>\n<p>Nun m&uuml;ssen wir noch daf&uuml;r sorgen, dass die Prozedur erkennt, dass sie mehrfach f&uuml;r das gleiche Element ausgel&ouml;st wird und dementsprechend nicht einfach den Text in das Feld <b>Bemerkungen <\/b>schreibt, sondern diesen an den bereits enthaltenen Text anh&auml;ngt.<\/p>\n<p>Dazu nehmen wir drei kleine &auml;nderungen vor, die Sie in Listing 22 in fetter Schrift finden.<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>intCounter<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>IVBSAXContentHandler_startElement(strNamespaceURI<span style=\"color:blue;\"> As String<\/span>, _\r\n         strLocalName<span style=\"color:blue;\"> As String<\/span>, strQName<span style=\"color:blue;\"> As String<\/span>, _\r\n         ByVal oAttributes<span style=\"color:blue;\"> As <\/span>MSXML2.IVBSAXAttributes)\r\n     ...\r\n     intCounter = 0\r\n     ...\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>IVBSAXContentHandler_characters(strChars<span style=\"color:blue;\"> As String<\/span>)\r\n     ...\r\n     Select Case strFeld\r\n         ...\r\n         <span style=\"color:blue;\">Case <\/span>\"Bemerkungen\"\r\n             <span style=\"color:blue;\">If <\/span>intCounter = 0<span style=\"color:blue;\"> Then<\/span>\r\n                 rstKunden!Bemerkungen = strChars\r\n             <span style=\"color:blue;\">Else<\/span>\r\n                 rstKunden!Bemerkungen = rstKunden!Bemerkungen & strChars\r\n             <span style=\"color:blue;\">End If<\/span>\r\n         ...\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n     intCounter = intCounter + 1\r\n     ...\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 22: Notwendige &auml;nderungen, um mehrteilige Texte einzulesen<\/span><\/b><\/p>\n<p>Zun&auml;chst deklarieren wir dort im Kopf des Moduls eine Variable namens <b>intCounter<\/b>. Diese stellen wir in der Ereignisprozedur <b>IVBSAXContentHandler_startElement <\/b>jeweils auf den Wert <b>0 <\/b>ein, also immer, wenn ein neues Element eingelesen wird.<\/p>\n<p>In der Ereignisprozedur <b>IVBSAXContentHandler_characters <\/b>schlie&szlig;lich pr&uuml;fen wir f&uuml;r das entsprechende Element, hier Bemerkungen, ob die Z&auml;hlervariable <b>intCounter <\/b>den Wert <b>0 <\/b>oder einen anderen Wert enth&auml;lt. Im Falle des Wertes <b>0 <\/b>handelt es sich um den ersten (und gegebenenfalls auch letzten) Teil und wir k&ouml;nnen diesen einfach als Wert des Feldes <b>Bemerkungen<\/b> in die Tabelle eintragen. Sollte <b>intCounter <\/b>einen Wert gr&ouml;&szlig;er als <b>0 <\/b>enthalten, ist dies nicht der erste Teil und wir h&auml;ngen den aktuellen Wert von <b>strChars <\/b>an den bereits vorhandenen Text im Feld <b>Bemerkungen <\/b>an.<\/p>\n<p><b>Zusammenfassung und Ausblick<\/b><\/p>\n<p>In diesem Beitrag haben Sie einige einfache Beispiele f&uuml;r das Einlesen von Daten mit dem SAX-Parser kennengelernt. Durch die ereignisbasierte Herangehensweise ergibt sich eine teilweise recht umst&auml;ndliche Programmierung, die erheblich von der gewohnten Methode mit dem DOM-Parser abweicht.<\/p>\n<p>Wenn Sie jedoch umfangreiche Dokumente einlesen m&uuml;ssen, was unter DOM recht lange dauern kann oder, wenn die Datei zu gro&szlig; ist, komplett scheitert, ist SAX eine gute Wahl.<\/p>\n<h3>Downloads zu diesem Beitrag<\/h3>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>SAXPraxis.mdb<\/p>\n<p>KundeMitAnrede.xml<\/p>\n<p>MehrteiligeTexte.xml<\/p>\n<p>Beispiel.xml<\/p>\n<p>Fahrzeuge.xml<\/p>\n<p>Kunde.xml<\/p>\n<p>KundeMitAdresse.xml<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/{E8D65DF3-7404-487E-8360-ED6E412E75F4}\/aiu_970.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Im Beitrag XML-Dokumente mit SAX parsen haben wir die Grundlagen ds SAX-Parsers vorgestellt. Dabei sind wir soweit gekommen, dass wir den kompletten Inhalt einer XML-Datei im Direktbereich des VBA-Editors ausgegeben haben. Das kann nat&uuml;rlich nicht alles sein: Die Daten sollen ja in der Regel in den Tabellen der Datenbank landen. Den Ereignisprozeduren, welche das XML-Dokument sequenziell durchlaufen, m&uuml;ssen wir dabei nat&uuml;rlich noch die eine oder andere zus&auml;tzliche Anweisung hinzuf&uuml;gen, damit die Daten an der gew&uuml;nschten Stelle gespeichert werden.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[66012015,662015,44000026],"tags":[],"class_list":["post-55000970","post","type-post","status-publish","format-standard","hentry","category-66012015","category-662015","category-Interaktiv"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.4) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>SAX: XML-Dokumente parsen in der Praxis - Access im Unternehmen<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/access-im-unternehmen.de\/SAX_XMLDokumente_parsen_in_der_Praxis\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"SAX: XML-Dokumente parsen in der Praxis\" \/>\n<meta property=\"og:description\" content=\"Im Beitrag XML-Dokumente mit SAX parsen haben wir die Grundlagen ds SAX-Parsers vorgestellt. Dabei sind wir soweit gekommen, dass wir den kompletten Inhalt einer XML-Datei im Direktbereich des VBA-Editors ausgegeben haben. Das kann nat&uuml;rlich nicht alles sein: Die Daten sollen ja in der Regel in den Tabellen der Datenbank landen. Den Ereignisprozeduren, welche das XML-Dokument sequenziell durchlaufen, m&uuml;ssen wir dabei nat&uuml;rlich noch die eine oder andere zus&auml;tzliche Anweisung hinzuf&uuml;gen, damit die Daten an der gew&uuml;nschten Stelle gespeichert werden.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/SAX_XMLDokumente_parsen_in_der_Praxis\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2020-05-22T21:06:56+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg07.met.vgwort.de\/na\/f7e77357a48747388217f3793fb29747\" \/>\n<meta name=\"author\" content=\"Andr\u00e9 Minhorst\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andr\u00e9 Minhorst\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"30\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SAX_XMLDokumente_parsen_in_der_Praxis\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SAX_XMLDokumente_parsen_in_der_Praxis\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"SAX: XML-Dokumente parsen in der Praxis\",\"datePublished\":\"2020-05-22T21:06:56+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SAX_XMLDokumente_parsen_in_der_Praxis\\\/\"},\"wordCount\":4595,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SAX_XMLDokumente_parsen_in_der_Praxis\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/f7e77357a48747388217f3793fb29747\",\"articleSection\":[\"1\\\/2015\",\"2015\",\"Interaktiv\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/SAX_XMLDokumente_parsen_in_der_Praxis\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SAX_XMLDokumente_parsen_in_der_Praxis\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SAX_XMLDokumente_parsen_in_der_Praxis\\\/\",\"name\":\"SAX: XML-Dokumente parsen in der Praxis - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SAX_XMLDokumente_parsen_in_der_Praxis\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SAX_XMLDokumente_parsen_in_der_Praxis\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/f7e77357a48747388217f3793fb29747\",\"datePublished\":\"2020-05-22T21:06:56+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SAX_XMLDokumente_parsen_in_der_Praxis\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/SAX_XMLDokumente_parsen_in_der_Praxis\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SAX_XMLDokumente_parsen_in_der_Praxis\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/f7e77357a48747388217f3793fb29747\",\"contentUrl\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/f7e77357a48747388217f3793fb29747\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SAX_XMLDokumente_parsen_in_der_Praxis\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"SAX: XML-Dokumente parsen in der Praxis\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"name\":\"Access im Unternehmen\",\"description\":\"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access\",\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/access-im-unternehmen.de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\",\"name\":\"Andr\u00e9 Minhorst Verlag\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"contentUrl\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"width\":370,\"height\":111,\"caption\":\"Andr\u00e9 Minhorst Verlag\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\",\"name\":\"Andr\u00e9 Minhorst\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"caption\":\"Andr\u00e9 Minhorst\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"SAX: XML-Dokumente parsen in der Praxis - Access im Unternehmen","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/access-im-unternehmen.de\/SAX_XMLDokumente_parsen_in_der_Praxis\/","og_locale":"de_DE","og_type":"article","og_title":"SAX: XML-Dokumente parsen in der Praxis","og_description":"Im Beitrag XML-Dokumente mit SAX parsen haben wir die Grundlagen ds SAX-Parsers vorgestellt. Dabei sind wir soweit gekommen, dass wir den kompletten Inhalt einer XML-Datei im Direktbereich des VBA-Editors ausgegeben haben. Das kann nat&uuml;rlich nicht alles sein: Die Daten sollen ja in der Regel in den Tabellen der Datenbank landen. Den Ereignisprozeduren, welche das XML-Dokument sequenziell durchlaufen, m&uuml;ssen wir dabei nat&uuml;rlich noch die eine oder andere zus&auml;tzliche Anweisung hinzuf&uuml;gen, damit die Daten an der gew&uuml;nschten Stelle gespeichert werden.","og_url":"https:\/\/access-im-unternehmen.de\/SAX_XMLDokumente_parsen_in_der_Praxis\/","og_site_name":"Access im Unternehmen","article_published_time":"2020-05-22T21:06:56+00:00","og_image":[{"url":"http:\/\/vg07.met.vgwort.de\/na\/f7e77357a48747388217f3793fb29747","type":"","width":"","height":""}],"author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"30\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/SAX_XMLDokumente_parsen_in_der_Praxis\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/SAX_XMLDokumente_parsen_in_der_Praxis\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"SAX: XML-Dokumente parsen in der Praxis","datePublished":"2020-05-22T21:06:56+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/SAX_XMLDokumente_parsen_in_der_Praxis\/"},"wordCount":4595,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/SAX_XMLDokumente_parsen_in_der_Praxis\/#primaryimage"},"thumbnailUrl":"http:\/\/vg07.met.vgwort.de\/na\/f7e77357a48747388217f3793fb29747","articleSection":["1\/2015","2015","Interaktiv"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/SAX_XMLDokumente_parsen_in_der_Praxis\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/SAX_XMLDokumente_parsen_in_der_Praxis\/","url":"https:\/\/access-im-unternehmen.de\/SAX_XMLDokumente_parsen_in_der_Praxis\/","name":"SAX: XML-Dokumente parsen in der Praxis - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/SAX_XMLDokumente_parsen_in_der_Praxis\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/SAX_XMLDokumente_parsen_in_der_Praxis\/#primaryimage"},"thumbnailUrl":"http:\/\/vg07.met.vgwort.de\/na\/f7e77357a48747388217f3793fb29747","datePublished":"2020-05-22T21:06:56+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/SAX_XMLDokumente_parsen_in_der_Praxis\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/SAX_XMLDokumente_parsen_in_der_Praxis\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/SAX_XMLDokumente_parsen_in_der_Praxis\/#primaryimage","url":"http:\/\/vg07.met.vgwort.de\/na\/f7e77357a48747388217f3793fb29747","contentUrl":"http:\/\/vg07.met.vgwort.de\/na\/f7e77357a48747388217f3793fb29747"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/SAX_XMLDokumente_parsen_in_der_Praxis\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"SAX: XML-Dokumente parsen in der Praxis"}]},{"@type":"WebSite","@id":"https:\/\/access-im-unternehmen.de\/#website","url":"https:\/\/access-im-unternehmen.de\/","name":"Access im Unternehmen","description":"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access","publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/access-im-unternehmen.de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/access-im-unternehmen.de\/#organization","name":"Andr\u00e9 Minhorst Verlag","url":"https:\/\/access-im-unternehmen.de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/","url":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","contentUrl":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","width":370,"height":111,"caption":"Andr\u00e9 Minhorst Verlag"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f","name":"Andr\u00e9 Minhorst","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","caption":"Andr\u00e9 Minhorst"}}]}},"_links":{"self":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55000970","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/comments?post=55000970"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55000970\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55000970"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55000970"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55000970"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}