Von Word zu Access-Richtext/HTML

Das mit Access 2007 eingeführte Richtext-Format ist für viele Anwendungen interessant. Die Eingabe und Formatierung ist aber nicht wirklich ergonomisch – da sind Sie von Word mehr Komfort gewohnt. Warum aber nicht die Texte in Word eingeben und dann nach Access übernehmen Alles, was Sie brauchen, sind einige Grundlagenkenntnisse über den Aufbau von Dokumenten in Word und die Absatz- und Zeichenvorlagen sowie zwei oder drei Tricks – schon haben Sie den Inhalt eines Word-Dokuments samt Formatierungen in ein Memofeld mit Richtext-Formatierung überführt.

Damit erschlagen Sie dann gleich zwei Fliegen mit einer Klappe: Sowohl bereits existierende als auch neu erstellte Dokumente können Sie so recht einfach nach Access überführen.

Einzige Voraussetzung für die Verwendung der in diesem Beitrag vorgestellten Techniken ist, dass Sie die Absätze mit entsprechenden Absatzformatvorlagen versehen haben und hervorgehobene Texte mit entsprechenden Zeichenformatvorlagen. Wenn Sie das nicht tun, wäre nun ein guter Zeitpunkt, um damit zu beginnen!

Schauen wir uns zunächst einmal an, welche Formatierungen uns das Richtext-Format von Access bietet.

Eins vorweg: Wir können keine eigenen Formate definieren und auch nicht die gängigen Absatzformate wie h1, h2, h3 oder p verwenden. Deshalb ist das übertragen von Inhalten mit benannten Absatz- und Zeichenformatvorlagen eine Einbahnstraße.

Um die einzelnen Formatierungen zu erkennen, erstellen wir ein Experimentierformular mit zwei Textfeldern. Das erste zeigt den Inhalt im Richtext-Format an, das zweite soll den Inhalt mit HTML-Auszeichnungen anzeigen. In der Formularansicht sieht dies wie in Bild 1 aus.

Anzeige der HTML-Version der formatierten Texte

Bild 1: Anzeige der HTML-Version der formatierten Texte

Der jeweils eingegebene oder formatierte Text wird gleich nach jeder änderung im rechten Textfeld mit HTML-Auszeichnungen angezeigt. Dafür sorgt die folgende Ereignisprozedur, die durch das Ereignis Bei änderung ausgelöst wird:

Private Sub txtRichtext_Change()
     Me!txtHTML = Me!txtRichtext.Text
End Sub

Damit das Betätigen der Eingabetaste im linken Textfeld zum Einfügen eines Zei-len-umbruchs führt und nicht zum Wechsel zum rechten Textfeld, stellen Sie die Eigenschaft Eingabetastenverhalten auf den Wert Neue Zeile im Feld ein.

Nun brauchen Sie nur noch die zur Verfügung stehenden Formatierungen anzuwenden und können dann rechts die jeweiligen HTML-Auszeichnungen abgreifen.

Das Ergebnis sieht wie folgt aus – hier zunächst für die Absatzformatierungen:

  • <div>Einfacher Absatz</div>
  • Leerer Absatz: <div> </div>
  • <div>Links zentrierter Absatz.</div>
  • <div align=center>Mittig zentrierter Absatz.</div>
  • <div align=right>Rechts zentrierter Absatz.</div>
  • <ul> <li>Auflistung, erster Punkt</li> <li>Auflistung, zweiter Punkt</li></ul>
  • <ol> <li>Aufzählung, erster Punkt</li> <li>Aufzählung, zweiter Punkt</li></ol>
  • <strong>fette </strong>Schrift
  • <em>kursiver </em>Schrift
  • <u>unterstrichener </u>Schrift
  • <strong><em>fette, kursive </em></strong>Schrift
  • <font face=”Arial Narrow”>andere </font>Schriftart
  • <font size=4>andere </font>Schriftgröße
  • <font color=red>farbige </font>Schrift
  • <font style=”BACKGROUND-COLOR:#FFFF00″>farbiger </font>Hintergrund
  • <div>Absatz mit weichemZeilenumbruch</div> (Achtung: Bei einer weiteren änderung des Inhalts wird dieser durch </div><div> ersetzt!)
  • <blockquote><div>Zitatabsatz</div></blockquote>

Dokumentinhalt speichern

Nun schauen wir uns an, wie wir das Dokument beziehungsweise die einzelnen Absätze in der Datenbank speichern können. Die einfachste Möglichkeit ist, einfach für jeden Absatz einen neuen Datensatz zu einer Tabelle hinzuzufügen. Auf diese Weise können wir später ganz einfach auf die einzelnen Absätze zugreifen und diese nach Wunsch beispielsweise mit verschiedenen Formatierungen ausstatten.

Die Tabelle für diesen Zweck soll nicht nur ein Dokument gleichzeitig aufnehmen, sondern gegebenenfalls auch einmal mehrere – deshalb müssen wir der Tabelle noch ein Feld hinzufügen, welches einen Hinweis auf das Ursprungsdokument liefert. Da dies typischerweise der Dateiname sein wird und wir dieses nicht in jedem Datensatz für dieses Dokument wiederholen möchten, gliedern wir den Dateinamen in eine eigene Tabelle aus, die wir dann mit der Tabelle mit den Inhalten verknüpfen.

Diese Tabelle heißt tblDokumente und enthält neben dem Primärschlüsselfeld DokumentID lediglich ein weiteres Feld namens Dokument, welches den Pfad zu der betroffenen Datei enthält. Dieses Feld versehen wir mit einem eindeutigen Index, damit jedes Dokument nur einmal angegeben werden kann (s. Bild 2).

Tabelle zum Speichern der Dokumentnamen

Bild 2: Tabelle zum Speichern der Dokumentnamen

Die Tabelle tblAbsaetze, welche die Inhalte der einzelnen Absätze aufnehmen soll, finden Sie im Entwurf in Bild 3. Diese Tabelle enthält natürlich ein Fremdschlüsselfeld, mit dem das Dokument aus der Tabelle tblDokumente ausgewählt werden kann, zu dem der Absatz gehört. Außerdem besitzt die Tabelle das Feld Inhalt zum Speichern des Inhalts des jeweiligen Absatzes. Schließlich fehlt noch das Feld AbsatzformatID. Genau wie bei den Dokumenten könnten wir die Bezeichnung des Absatzformats direkt in ein Textfeld der Tabelle tblAbsaetze eintragen. Allerdings verwenden wir auch hier eine Lookup-Tabelle, die in diesem Fall noch weitere Felder enthält – zum Beispiel HTML-Tags, die wir später zum Erzeugen eines Dokuments im Richtext-Format von Access nutzen können (dazu später mehr). Diese Tabelle heißt tblAb-satz-formate und sieht in der Entwurfsansicht wie in Bild 4 aus. Auch für das Feld Absatzformat dieser Tabelle legen wir einen eindeutigen Index fest, damit jede Bezeichnung eines Absatzformats nur einmal in der Tabelle gespeichert werden kann.

Tabelle zum Speichern der Absatzformate eines Dokuments

Bild 3: Tabelle zum Speichern der Absatzformate eines Dokuments

Tabelle zum Speichern der Absätze eines Dokuments

Bild 4: Tabelle zum Speichern der Absätze eines Dokuments

Formular zum Einlesen der Dokumente

Um die Absätze, Formate und den Richtext für die eingelesenen Dokumente anzuzeigen, verwenden wir das Formular frmDokumente aus Bild 5.

Formular zum Einlesen und Anzeigen der Dokumente

Bild 5: Formular zum Einlesen und Anzeigen der Dokumente

Dieses verwendet die Tabelle tblDokumente als Datenherkunft. Das Unterformular in diesem Formular wiederum heißt sfmDokumente und soll die in der Tabelle tblAbsaetze gespeicherten Absätze zu dem im Hauptformular angezeigten Formular darstellen. Es verwendet die Tabelle tblAbsaetze als Datenherkunft. Damit das Unterformular jeweils die passenden Datensätze anzeigt, stellen Sie die beiden Eigenschaften Verknüpfen von und Verknüpfen nach des Unterformular-Steuerelements auf den Wert DokumentID ein.

Neben dem Textfeld txtDokument, das an das Feld Dokument der Datenherkunft gebunden ist, finden Sie eine Schaltfläche namens cmdDateiAuswaehlen. Diese ruft die Prozedur aus Listing 1 auf.

Private Sub cmdDateiAuswaehlen_Click()
     Dim strDokument As String
     Dim lngDokumentID As Long
     strDokument = OpenFileName(CurrentProject.Path, "Dokument auswählen", _
         "Word-Dokumente (*.doc;*.docx)")
     lngDokumentID = WordDokumentEinlesen(strDokument)
     If Len(lngDokumentID) > 0 Then
         Me.Requery
         Me.Recordset.FindFirst "DokumentID = " & lngDokumentID
         Me!sfmDokumente.Form.Requery
         Me!txtRichtext = RichTextErstellen(Me!DokumentID)
     End If
End Sub

Listing 1: Auswählen und Einlesen des Inhalts eines Word-Dokuments

Die Prozedur öffnet zunächst einen Datei öffnen-Dialog und weist das Ergebnis der Variablen strDokument zu. Dann ruft es eine Funktion namens WordDokumentEinlesen auf und übergibt dieser den Namen des einzulesenden Word-Dokuments. Diese Funktion steuert das Einlesen des Word-Dokuments und trägt die Inhalte der einzelnen Absätze in die Tabellen tblDokumente und tblAbsaetze ein. War dieser Vorgang erfolgreich, liefert sie den Primärschlüsselwert des neuen Datenatzes der Tabelle tblDokumente zurück. Die Prozedur cmdDateiAus-waehlen_Click aktualisiert dann seine Datenherkunft, stellt den Datensatzzeiger auf den neuen Datensatz ein und aktualisiert auch den Inhalt des Unterformulars. Dann erstellt sie mithilfe der Funktion RichtextErstellen aus den gewonnenen Daten einen Text im Richtext-Format von Access.

In der Praxis sollte dies dann wie in Bild 6 aussehen.

Darstellung eines Dokuments mit den einzelnen Absätzen und mit dem resultierenden Richtext-Dokument

Bild 6: Darstellung eines Dokuments mit den einzelnen Absätzen und mit dem resultierenden Richtext-Dokument

Dokument einlesen

Die grundlegenden Techniken zum öffnen und Einlesen des Word-Dokuments sowie zum Ausstatten des Word-Dokuments mit entsprechenden Format- und Zeichenformatvorlagen finden Sie im Beitrag Word-Dokumente einlesen (www.access-im-unternehmen.de/943). Die dort vorgestellte Prozedur WordDokumentEinlesen haben wir noch etwas verfeinert, sodass diese nun wie in Listing 2 aussieht. Auch hier benötigen wir eine Variable, die den Verweis auf die Word-Instanz speichert – diese deklarieren wir wie folgt:

Public Sub WordDokumentEinlesen(strDokument As String)
     Dim objDokument As Word.Document
     Dim objAbsatz As Word.Paragraph
     Dim lngDokumentID As Long
     Set objDokument = DokumentOeffnen(strDokument)
     If objDokument Is Nothing Then
         MsgBox "Das Dokument wurde nicht gefunden."
         Exit Sub
     End If
     objWord.Visible = True
     FettErsetzen objDokument
     KursivErsetzen objDokument
     lngDokumentID = DokumentSpeichern(strDokument)
     If Not lngDokumentID = 0 Then
         For Each objAbsatz In objDokument.Paragraphs
                 AbsatzSpeichern objAbsatz.Range.ParagraphStyle, objAbsatz.Range.Text, lngDokumentID
         Next objAbsatz
     End If
     DokumentSchliessen objDokument
End Sub

Listing 2: Steuerungsprozedur zum Einlesen des Word-Dokuments

Dim objWord As Word.Application

Die Prozedur erwartet den Namen der einzulesenden Datei als Parameter. Die Prozedur DokumentOeffnen (siehe im oben genannten Beitrag) öffnet das Dokument und übergibt einen Verweis auf dieses Dokument an die Objektvariable objDokument.

Sollte diese Variable anschließend leer sein, konnte das Dokument offensichtlich nicht geöffnet werden, was in einer entsprechenden Meldung resultiert. Das Word-Fenster wird eingeblendet (dies können Sie auch weglassen) und die beiden Prozeduren FettErsetzen und KursivErsetzen sorgen dafür, dass die entsprechenden formatierten Passagen im Dokument mit öffnenden und schließenden HTML-Tags wie oder eingeschlossen werden.

Dann legt die Prozedur über die Funktion DokumentSpeichern einen neuen Datensatz für das Dokument in der Tabelle tblDokumente an.

Die Funktion liefert den Primärschlüsselwert des neuen Datensatzes zurück, damit diese beim Anlegen der Datensätze in der Tabelle tblAbsaetze als Fremdschlüsselwert verwendet werden kann. Mehr zu dieser Funktion lesen Sie weiter unten.

Sollte die Funktion einen Primärschlüsselwert ungleich 0 zurückliefern, durchläuft die Prozedur in einer For Each-Schleife alle Absätze des Word-Dokuments, welche über die Paragraphs-Auflistung bereitgestellt werden.

Innerhalb der Schleife ruft die Prozedur dann die Routine AbsatzSpeichern auf, die sich um das Anlegen des Datensatzes für den aktuellen Absatz in der Tabelle tblAbsaetze kümmert – siehe weiter unten. Anschließend ruft sie die Prozedur DokumentSchliessen auf, um das soeben eingelesene Dokument zu schließen.

Dokument-Datensatz speichern

Die Funktion DokumentSpeichern erwartet als Parameter die Angabe des Dokumentpfades, für das ein neuer Datensatz in der Tabelle tblDokumente angelegt werden soll (s. Listing 3).

Public Function DokumentSpeichern(strDokument As String) As Long
     Dim db As DAO.Database
     Dim intError As Integer
     Dim lngDokumentID As Long
     Set db = CurrentDb
     On Error Resume Next
     db.Execute "INSERT INTO tblDokumente(Dokument) VALUES(''" & strDokument & "'')", dbFailOnError
     intError = Err.Number
     On Error GoTo 0
     Select Case intError
         Case 3022
             If MsgBox("Ein gleichnamiges Dokument ist bereits vorhanden. " _
                     & "überschreiben (Ja) oder unter neuem " _
                     & "Namen speichern (Nein)", vbYesNo, "Dokument vorhanden") = vbYes Then
                 lngDokumentID = DLookup("DokumentID", "tblDokumente", _
                     & "Dokument = ''" & strDokument & "''")
                 db.Execute "DELETE FROM tblAbsaetze WHERE DokumentID = " & lngDokumentID
             Else
                 If BezeichnungErmitteln(strDokument, "tblDokumente", "DokumentID", "Dokument") _
                     = True Then
                         db.Execute "INSERT INTO tblDokumente(Dokument) VALUES(''" & strDokument & "'')"
                         lngDokumentID = db.OpenRecordset("SELECT @@IDENTITY").Fields(0)
                 End If
             End If
         Case 0
             lngDokumentID = db.OpenRecordset("SELECT @@IDENTITY").Fields(0)
         Case Else
             MsgBox "Fehler " & Err.Number & ", ''" & Err.Description & "''"
     End Select
     DokumentSpeichern = lngDokumentID
     Set db = Nothing
End Function

Listing 3: Speichern des Datensatzes für das Word-Dokument

Sie versucht dann zunächst, einen Datensatz mit dem angegebenen Dokumentpfad in der Tabelle tblDokument zu speichern – und zwar etwa mit der folgenden INSERT INTO-Anweisung:

INSERT INTO tblDokumente(Dokument) VALUES(''c:\Beispiel.docx'')

Wenn bereits ein Datensatz mit diesem Dokumentpfad vorhanden ist, löst dies einen Fehler aus, da das Feld Dokument mit einem eindeutigen Index ausgestattet wurde. Damit dies nicht die übliche Fehlermeldung hervorruft, haben wir mit der Anweisung On Error Resume Next die Fehlerbehandlung deaktiviert. Stattdessen speichern wir nach dem Ausführen der INSERT INTO-Anweisung die Fehlernummer in der Variablen intError und aktivieren die Fehlerbehandlung mit On Error Goto 0 wieder.

Danach analyisiert die Prozedur den Inhalt von intError in einer Select Case-Bedingung. Hat intError den Wert 3022, war offensichtlich bereits ein Datensatz mit diesem Dokument vorhanden. In diesem Fall fragt die Anwendung, ob dieser Datensatz überschrieben werden soll (Ja) oder ob der Benutzer einen neuen Pfad angeben möchte (Nein).

Im ersten Fall haben wir es leicht: Wir müssen einfach nur den Primärschlüsselwert für den bereits vorhandenen Datensatz per DLookup ermitteln und die bereits in der Tabelle tblAbsaetze gespeicherten Datensätze löschen, da diese ja gleich neu eingelesen werden sollen. Dies erledigt beispielsweise die folgende SQL-Anweisung:

DELETE FROM tblAbsaetze 
WHERE DokumentID = 5

Möchte der Benutzer hingegen einen neuen Dokumentpfad angeben, müssen wir diesen zunächst abfragen. Dazu nutzen wir die Funktion Bezeichnung-Ermitteln, die den Benutzer solange nach einem neuen Dokumentpfad fragt, bis diese einen noch nicht in der Tabelle enthaltenen Text angegeben oder den Vorgang abgebrochen hat. Die Funktion schreibt die neue Bezeichnung in die Variable strDokument, die anschließend weiter verwendet wird – aber nur, wenn BezeichnungErmitteln den Wert True zurückliefert. Diese Funktion schauen wir uns im Beitrag Neue Werte in eindeutigen Feldern (www.access-im-unternehmen.de/941) an.

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

den kompletten Artikel im PDF-Format mit Beispieldatenbank

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar