Einen Artikel hab ich leider nicht, aber ich kann in Etwa aufzeigen wie wir das gemacht haben (Bitte aber um Verständnis, dass ich nicht den kompletten Code posten werde, insbesondere das XSLT da doch relativ viel Know how darinsteckt. Der Code ist weiterhin stark verkürzt, ich hab mir erlaubt die meisten DIM's weg zu lassen
)
' also, als erstes brauchen wir hier eine Klasse die das als "Einheit" zusammenfasst
Public Class FocConvertRtfToMime As FocSldObject
private state as integer ' Variable für die Statemachine
currElement as string ' aktuelles Element
' Die DXL-Konvertierungsmethode
Private Function doDxlConversion(doc As NotesDocument, item As String, htmlStream As NotesStream)
Set exporter = session.CreateDXLExporter
exporter.ConvertNotesbitmapsToGIF = True ' Pflicht
Call exporter.SetInput(doc)
Set parser = session.CreateSAXParser(exporter)
' Hier werden die Callbacks des Sax-Parsers registriert
On Event SAX_StartElement From parser Call SAXStart
On Event SAX_Characters From parser Call SAXChar
On Event SAX_EndElement From parser Call SAXEnd
Set xsltStream = session.CreateStream
Call xsltStream.WriteText(XSLT_TRANSFORM) ' hier das XSLT welches sich für die RTF->HTML-Übersetzung kümmert
' Die Idee die dahinter steckt stammen aus http://pd4ml.com/i/Dev_Spellman_Leverage%20DXL.pdf
xsltStream.Position = 0
Set transformer = session.CreateXSLTransformer(parser,xsltStream,htmlStream)
Call exporter.process() ' Stößt die Kette DXL-Export->SAX->XSLT an. Das fertige HTML steht nun in htmlstream
end function
' Diese Sub wird immer dann aufgerufen, wenn der Saxparser an einen öffnenden Tag vorbei kommt
Sub SAXstart (Source As Notessaxparser, Byval elementname As String, Attributes As NotesSaxAttributeList)
Select Case (elementname)
Case "item":
If Lcase(Attributes.GetValue("name"))="body" Then
state = START_CONVERT
End If
End Select
currElement = elementname ' aktuellen Elementnamen merken (für saxchar)
if (state >= START_CONVERT) then
Source.Output("<" + elementname) ' element 1:1 nach Output (sprich XSLT) schreiben
i = Attributes.Length
While(i > 0) ' Nun noch die Attribute schreiben (umständlich, geht leider nicht anders)
Call source.Output(" " +Attributes.GetName(i)+"=")
Call source.Output({"} +FocXMLTools.escape(Attributes.GetValue(i))+ {"})
i = i - 1
Wend
Source.Output(">") ' fertig
end if
end sub
' wird immer nach SaxStart aufgerufen, wenn Zeichen im jeweiligen Tag enthalten sind
Sub SAXChar (Source As Notessaxparser, Byval Characters As String, Count As Long)
if state < START_CONVERT then exit sub ' noch nichts zu tun
Select Case currElement
Case "gif","jpeg": Source.Output(createImage(characters, currElement)) ' einen Anhang erzeuten
Case Else: Source.Output(FocXMLTools.escape(characters)) ' Stream 1:1 an den XSL-Transformer weitergeben
End Select
end sub
' wird beim schließenden Tag aufgerufen (Tags wie <par/> rufen unmittelbar saxStart + saxEnd auf)
Sub SAXend (Source As Notessaxparser, Byval ElementName As String)
if state < START_CONVERT then exit sub ' noch nichts zu tun
if currElement = "item" then state = STOP_CONVERT
end sub
' erzeugt Bild
Private Function createImage(base64content As String, imagetype As String) As String
call writeBase64ToMime(base64content, "image" + imgCount + "." +imagetype) ' Das Bild in das Mime-Feld schreiben
createImage = "<img src = 'image" + imgCount + "." +imagetype +"'/>" ' entsprechenden HTML-Tag generieren
end function
end class
Im Wesentlichen ist dies also eine Pipeline aus DXL-Export->SAX->XSLT->Notesstream wobei der Sax-Parser hier eine vorverarbeitung macht, in dem er GIF/JPEG-Tags als Attachments eines MIME-Entities schreibt und den restl. DXL-Stream an den XSLT weiter leitet. Dieser macht dann die restl. Konvertierung von RTF->HTML (er macht es noch nicht perfekt, aber besser als der HTTP-Task in Notes
)
Den SAX-Teil hab ich mit den notwendigen Callbacks und Statusvariablen in eine eigene Klasse gepackt (so wie es sich gehört
), dann wirds übersichtlich(er)
Ich hoffe ich konnte dir und evtl ein paar anderen die zündende Idee liefertn
Gruß
Roland