Live-Forum - Die aktuellen Beiträge
Anzeige
Archiv - Navigation
1188to1192
Aktuelles Verzeichnis
Verzeichnis Index
Übersicht Verzeichnisse
Vorheriger Thread
Rückwärts Blättern
Nächster Thread
Vorwärts blättern
Anzeige
HERBERS
Excel-Forum (Archiv)
20+ Jahre Excel-Kompetenz: Von Anwendern, für Anwender
Inhaltsverzeichnis

Zellinhalte in HTML verwandeln

Zellinhalte in HTML verwandeln
rlx
Ich hatte unlängst unter dem Titel Auslesen von Formatierungen mit .characters angefragt, wie man abweichende Formatierungen innerhalb von Excel-Zellen in HTML-Code verwandeln kann.
In der Forums-FAQ werde ich aufgefordert, Feedback zu geben, ob ein Hinweis geholfen hat oder nicht, jedoch kann man ca. 5 Tage nach Erstellen eines Beitrages hier offenbar nicht mehr antworten, was ich erstens sehr ungewöhnlich, zweitens kommunikationserschwerend und drittens auch völlig bescheuert finde.
Das ist hier doch kein Allerwelts-Chat, wo das Geschreibsel am nächsten Tag schon keinen mehr interessiert, sondern ein Fachforum! Wozu diese Einschränkung?
So bin ich also gezwungen, für das Feedback einen neuen Thread zu eröffnen, welcher eigentlich keine Fragen, sondern nur meinen Lösungsweg enthält.
fcs (Franz) hatte zuletzt einen Vorschlag gemacht, der auf der Grundlage der RangeToHTML-Funktion von Ron de Bruin auch die Formate innerhalb von Zellen wiedergibt:


      
Function RangetoHTML1(rng As Range)
    
' Changed by Ron de Bruin 28-Oct-2006
    ' Working in Office 2000-2010
    ' bearbeitet von fcs
    Dim fso As Object
    
Dim ts As Object
    
Dim TempFile As String
    
Dim TempWB As Workbook
    
    TempFile = Environ$(
"temp") & "/" & Format(Now, "dd-mm-yy h-mm-ss") & ".htm"
    
    
'Copy the range and create a new workbook to past the data in
    Set TempWB = Workbooks.Add(1)
    
With TempWB.Sheets(1)
        rng.EntireColumn.Copy
        
'Spaltenbreiten kopieren
        .Cells(1, 1).PasteSpecial Paste:=xlPasteFormats
        .UsedRange.ClearFormats
        
'Zellbereich kopieren
        rng.Copy .Cells(1, 1)
        Application.CutCopyMode = 
False
        
On Error Resume Next
        .DrawingObjects.Visible = 
True
        .DrawingObjects.Delete
        
On Error GoTo 0
    
End With
    
    
'Publish the sheet to a htm file
    With TempWB.PublishObjects.Add( _
        SourceType:=xlSourceRange, _
        Filename:=TempFile, _
        Sheet:=TempWB.Sheets(1).Name, _
        Source:=TempWB.Sheets(1).UsedRange.Address, _
        HtmlType:=xlHtmlStatic)
        .Publish (
True)
    
End With
    
    
'Read all data from the htm file into RangetoHTML
    Set fso = CreateObject("Scripting.FileSystemObject")
    
Set ts = fso.GetFile(TempFile).OpenAsTextStream(1, -2)
    RangetoHTML1 = ts.ReadAll
    ts.Close
    RangetoHTML1 = Replace(RangetoHTML1, 
"align=center x:publishsource=", _
      
"align=left x:publishsource=")
    
    
'Close TempWB
    TempWB.Close savechanges:=False
    
    
'Delete the htm file we used in this function
    Kill TempFile
    
    
Set ts = Nothing
    
Set fso = Nothing
    
Set TempWB = Nothing
End Function 


Sein Codebeispiel war für mich in dieser Form unbrauchbar, weil damit u.U. mehrere hundert leere HTML-Tabellenzellen erzeugt wurden. Das hängt wohl mit dem Befehl rng.EntireColumn.Copy und dem anschließenden .Cells(1, 1).PasteSpecial Paste:=xlPasteFormats zusammen, was wohl dazu gedacht war, die Spaltenbreiten exakt zu übertragen, was aber für mich nicht wichtig ist, da im Endeffekt nur ein String entstehen soll, der keine HTML-Tabellendefinitionen enthält.
Aber immerhin: Die abweichenden Formate innerhalb von Zellen wurden in HTML-verwandelt. Und das, obwohl fcs an der entscheidenden Stelle gar keine PasteSpecial-Methode anwendet: rng.Copy .Cells(1, 1).
So ganz hab ich das zwar noch nicht kapiert (die VBA-Hilfe ist bei der Beschreibung von PasteSpecial leider sehr oberflächlich), aber mit rng.copy und anschließendem .Cells(1, 1).PasteSpecial geht es auch.
Da ich die Funktion innerhalb meines Programms ca. 1000 mal aufrufe, hatte ich dann zunächst das Erstellen des temporären Workbooks nach "außen" verlagert, d.h. es wurde nur einmal ein temporäres Workbook erstellt, welches der Funktion als Referenz übergeben wurde, die den Inhalt nach verrichteter Arbeit wieder gelöscht hat. Dann fiel mir auf, dass dieses temporäre Workbook an sich überflüssig ist, man kann ja auch direkt den gewünschten Range aus der primären Tabelle in die HTML-Datei schreiben.
So blieb dann übrig:


      
Function RangetoHTML3(rng As Range) As String
    
' Changed by Ron de Bruin 28-Oct-2006
    ' zusammengestutzt von fcb und rlx
    Dim wbt As Workbook
    
Dim fso As Object
    
Dim ts As Object
    
Dim TempFile As String
    
Dim TempWB As Workbook
  
    
Set wbt = rng.Parent.Parent
    TempFile = Environ$(
"temp") & "/" & Format(Now, "dd-mm-yy h-mm-ss") & ".htm"
  
    
'Zellbereich rng als HTML-Datei publizieren
    With wbt.PublishObjects.Add( _
        SourceType:=xlSourceRange, _
        Filename:=TempFile, _
        Sheet:=rng.Worksheet.Name, _
        Source:=rng.Address, _
        HtmlType:=xlHtmlStatic)
        .Publish (
True)
    
End With
  
    
'Daten aus temporärer HTML-Datei in Funktionsergebnis (String) schreiben
    Set fso = CreateObject("Scripting.FileSystemObject")
    
Set ts = fso.GetFile(TempFile).OpenAsTextStream(1, -2)
    RangetoHTML3 = ts.ReadAll
    ts.Close
    
    
'Temporäre HTML-Datei schließen
    Kill TempFile
  
    
Set ts = Nothing
    
Set fso = Nothing
    
Set TempWB = Nothing
End Function 


Das Ergebnis ist ein String, der eine komplette HTML-Seite mit head und body darstellt, darin ist dann eine einzige Tabelle mit nur einer einzigen Zelle, deren Inhalt Formatierungen enthält, die aber über Style-Klassen realisiert werden. ....

5
Beiträge zum Forumthread
Beiträge zu diesem Forumthread

Betreff
Benutzer
Anzeige
Zellinhalte in HTML verwandeln (2)
22.11.2010 16:03:59
rlx
Da gabs wohl ein technisches Problemchen. Also weiter:
Das Ergebnis ist ein String, der eine komplette HTML-Seite mit head und body darstellt, darin ist dann eine einzige Tabelle mit nur einer einzigen Zelle, deren Inhalt Formatierungen enthält, die aber über Style-Klassen realisiert werden. Diese Klassen sind im head in einem style-Tag definiert und tragen immer andere kryptische Namen, z.B. xl2515613 oder font615613. Da mein Projekt dem Erzeugen von HTML-Code für Artikel und Kommentare in Blogs bzw. Foren dient, kann ich das so nicht gebrauchen, denn da hat man i.d.R. keine Möglichkeit, eigene Style-Klassen zu definieren.
Deshalb konvertiere ich den Ergebnisstring aus der RangeToHTML-Funktion mit folgender Funktion in "simples" HTML:


      
Function fctHTMLSimpleConvert(strTG As StringAs String
    
'sucht die erste Tabellenzelle <td> in strTG und wandelt sie in simples HTML um
    Dim strE As String     'Ergebnisstring
    Dim pTD As Integer, pCA As Integer, pCE As Integer
    
Dim strClass As String
    
Dim pTA As Integer, pTE As Integer
    
Dim i As Integer
    
Dim bFett As Boolean, bKursiv As Boolean, bColor As Boolean
    
Dim strColor As String
    
    
'erstes <td> finden
    pTD = InStr(1, strTG, "<td")
    
'Anfang der allgemeinen Klassenbezeichnung für Zelle finden
    pCA = InStr(pTD, strTG, "class=") + Len("class=")
    
'Ende der Klassenbezeichnung finden
    pCE = InStr(pCA, strTG, " ")
    
'Klassenbezeichnung auslesen
    strClass = Mid(strTG, pCA, pCE - pCA)
    
'MsgBox "Klasse ist " & strC & "###"
    'Anfang des Textes finden
    pTA = InStr(pTD, strTG, ">") + 1
    
'Ende des Textes finden
    pTE = InStr(pTA, strTG, "</td>") - 1
    
    
'Erstes Zeichen: Format-Tag für FETT setzen
    If fctHTMLFormate(strTG, strClass, "w") = "700" Then
        strE = strE & 
"<b>"
        bFett = 
True
    
End If
    
'Erstes Zeichen: Format-Tag für KURSIV setzen
    If fctHTMLFormate(strTG, strClass, "s") = "italic" Then
        strE = strE & 
"<i>"
        bKursiv = 
True
    
End If
    
'Erstes Zeichen: Format-Tag für Schriftfarbe setzen
    strColor = fctHTMLFormate(strTG, strClass, "c")
    
If strColor <> "windowtext" Then
        strE = strE & 
"<span style=" & Chr(34) & "color: " & strColor & ";" & Chr(34) & ">"
        bColor = 
True
    
End If
    
    i = pTA
    
    
Do
        
If Mid(strTG, i, Len("<font")) = "<font" Then
            
'wird neuer Font-Tag gefunden, werden aktuell gesetzte Format-Tags zunächst geschlossen
            If bColor = True Then
                strE = strE & 
"</span>"
                bColor = 
False
            
End If
            
If bKursiv = True Then
                strE = strE & 
"</i>"
                bKursiv = 
False
            
End If
            
If bFett = True Then
                strE = strE & 
"</b>"
                bFett = 
False
            
End If
            
'alle Format-Tags werden neu gesetzt:
            'Anfang der Klassenbezeichnung finden
            pCA = InStr(i, strTG, "class=") + Len("class=")
            
'Ende der Klassenbezeichnung finden
            pCE = InStr(pCA, strTG, ">")
            
'Klassenbezeichnung auslesen
            strClass = Mid(strTG, pCA, pCE - pCA)
            
            
'Format-Tag für FETT setzen
            If fctHTMLFormate(strTG, strClass, "w") = "700" Then
                strE = strE & 
"<b>"
                bFett = 
True
            
End If
            
'Format-Tag für KURSIV setzen
            If fctHTMLFormate(strTG, strClass, "s") = "italic" Then
                strE = strE & 
"<i>"
                bKursiv = 
True
            
End If
            
'Format-Tag für Schriftfarbe setzen
            strColor = fctHTMLFormate(strTG, strClass, "c")
            
If strColor <> "windowtext" Then
                strE = strE & 
"<span style=" & Chr(34) & "color: " & strColor & ";" & Chr(34) & ">"
                bColor = 
True
            
End If
            
            i = i + (pCE - i) + 1
            
        
Else
            
If Mid(strTG, i, Len("</font>")) = "</font>" Then
                
'schließender </font>-Tag wird übergangen
                'geöffnete Format-Tags <b>, <i> und <span> werden erst bei "<font" geschlossen,
                'da beim ersten Auftreten von "<font" kein "</font>" voransteht
                i = i + Len("</font>")
            
Else
                
'zeichenweises Übernehmen des Textes
                strE = strE & Mid(strTG, i, 1)
                i = i + 1
            
End If
        
End If
        
    
Loop While i < pTE
    
    
'am Ende alle Tags schließen für "sauberes" HTML
    If bColor = True Then
        strE = strE & 
"</span>"
        bColor = 
False
    
End If
    
If bKursiv = True Then
        strE = strE & 
"</i>"
        bKursiv = 
False
    
End If
    
If bFett = True Then
        strE = strE & 
"</b>"
        bFett = 
False
    
End If
    
    fctHTMLSimpleConvert = strE
End Function 


Dazu gehört dann noch diese Funktion, die die Werte der Eigenschaften font-weight, font-style und color aus den Klassen ausliest:


      
Function fctHTMLFormate(strTE As String, strClass As String, strO As StringAs String
    
'sucht in strTE nach Klasse strClass und gibt Eigenschafts-Werte von
    '  -style ("normal" oder "italic")
    '  -weight ("400"[dünn] oder "700"[fett])
    '  -color ("windowtext"[normal/schwarz] oder Farbwert[Farbwort oder Hexa-Code])
    'zurück
    'Option strO: "s"=font-style "w"=font-weight "c"=color
    
    
Dim pClass As Integer, pA As Integer, pE As Integer
    
Dim strF As String
    
    
If strO = "s" Then strF = "font-style:"
    
If strO = "w" Then strF = "font-weight:"
    
If strO = "c" Then strF = "color:"
    
    pClass = InStr(1, strTE, 
"." & strClass) + Len("." & strClass)
    
    pA = InStr(pClass, strTE, strF) + Len(strF)
    pE = InStr(pA, strTE, 
";")
    
    fctHTMLFormate = Mid(strTE, pA, pE - pA)
End Function 


Mein Gesamtprogramm dauert bei ca. 1000 auszulesenden Zellen nunmehr regelmäßig ca 45 sec. Dank an alle, die geholfen haben.
mfg
Ralf
Anzeige
Ergänzung bezgl. PublishObjects
22.11.2010 18:23:06
rlx
Hmm, wie ich nun feststelle, hatte das Anlegen eines temporären Workbooks wohl doch einen Sinn. Es wird nämlich mit jedem Aufruf der Funktion RangetoHTML3 ein sogenanntes PublishObject erzeugt, welches - das war mir nicht klar - in der Arbeitsmappe erhalten bleibt und offenbar Informationen über Quelle und Ziel (Zellbereich und Webseite) festhält. Nach einem Komplettdurchlauf habe ich 1120 Publish-Objekte in der Mappe, nach dem nächsten 2240 usw. (kann erfragt werden mit ActiveWorkbook.PublishObjects.Count)
Die Datei wird dadurch sehr schnell immer größer.
Da diese Infos in meinem Fall sinnlos sind (die HTML-Datei wird ja eh gleich wieder gekillt), sollten die Publish-Objekte anschließend gelöscht werden. Da ich nicht so recht weiß, wie ich das zuletzt erstellte Objekt ansprechen soll, mache ich es nach erfolgtem Programmdurchlauf einfach am Stück:


      
Sub LoeschePublishObjects(wb As Workbook)
    
Dim objP As PublishObject
    
For Each objP In wb.PublishObjects
        objP.Delete
    
Next
End Sub 


Anzeige
Inzwischen 7 Tage, dafür aber endgültig!
22.11.2010 17:28:11
Luc:-?
Früher waren es mal 3, Rix,
mit Offen-Vermerk 7 und man konnte, wenn man wusste wie, auch noch später kommentieren, dann aber eh nur für die Nachwelt. Viell war das ja auch damals nicht von Dauer…
Grund dafür ist, dass das hier ein kommerzielles Forum der Art ist, das nicht mit Werbebannern, sondern mit den Antworten der Nutzer Geld verdient (steht auch in den Teilnahmebedingungen)! Dazu wdn die Beiträge zeitlich geordnet und portio­niert. Zeitlich unbegrenzte Antwortmöglichkeiten würden dieses System stören. Alles klar?
Gruß Luc :-?
AW: Inzwischen 7 Tage, dafür aber endgültig!
22.11.2010 18:37:20
rlx
Ja, alles klar. ;-)
Ich habe früher mal im Spotlight-Forum mitgemacht (Leute wie NoNet werden sich noch erinnern :-)), da konnte man zwar auch nicht ewig antworten, aber ich glaube es waren schon 4-6 Wochen.
Sei es wie es sei, ich kann's nicht ändern, aber gut finde ich es trotzdem nicht ...
Anzeige
Ach ja -rlx-; mit i spricht's sich besser! ;-) orT
22.11.2010 23:15:18
Luc:-?
Gruß Lucius
:-?

Beliebteste Forumthreads (12 Monate)

Anzeige

Beliebteste Forumthreads (12 Monate)

Anzeige
Anzeige
Anzeige