Das Notes Forum

Domino 9 und frühere Versionen => ND6: Entwicklung => Thema gestartet von: eknori am 30.04.06 - 15:18:58

Titel: RichText in RichText EINFÜGEN
Beitrag von: eknori am 30.04.06 - 15:18:58
Das Thema ist zu interessant, als daß es in einem anderen Thread untergehen sollte. Der Einstiegspunkt im Thema ist folgendes Posting http://atnotes.de/index.php?topic=30182.msg190470#msg190470
Die weitere Diskussion zur DXL Lösung findet ab jetzt hier statt ...

Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 30.04.06 - 17:18:26
So wie ich es nach dem Lesen der Designer Help zu DXLImport und DXLExport verstanden habe, lassen sich alle für ein InsertRTItem erforderlichen Operationen ohne IO Zugriffe auf die Festplatte, ausschließlich im Arbeitsspeicher ausführen.

Mit dem Ansatz, den ich hier beschreibe, ist es grundsätzlich auch möglich , den Insert an jede beliebige Stelle in eine RTItem zu machen. Letztendlich werden alle ( Insert ) Operationen an einer "Textdatei" durchgeführt. Und da muss man nur wissen, an welcher Stelle man einen weiteren String einfügen muss ...

Die Besonderheiten bei Attachments etc. lasen sich leicht mittels der Datenbank im Ursprungsthread herausfinden.
Einfach ein neues Sample erstellen, die gewünschten Elemente in das RT einfügen und einen DXLExport machen.

Den bisher verwendeten Code habe ich ausschließlich aus der Designer Hilfe zusammenkopiert ...


Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: flaite am 01.05.06 - 00:36:23
Es gibt 2 verschiedene Wege, die es vermutlich einfacher machen als über Text zu gehen:
1. xslt
2. xml-Dom (gibts eine LotusScript Api für)

Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 01.05.06 - 14:41:02
Irgendwie stehe ich mit XML und dem DOMParser auf Kriegsfusß.

Ich habe folgenden XML Export meines Dokuments

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE document SYSTEM 'xmlschemas/domino_7_0.dtd'>
<document xmlns='http://www.lotus.com/dxl' version='7.0' replicaid='C125715F002D73D1'
 form='Sample'>
<noteinfo noteid='916' unid='7EE586C3D6B725CCC1257160004210E3' sequence='26'>
<created><datetime dst='true'>20060430T140136,99+02</datetime></created>
<modified><datetime dst='true'>20060501T143234,46+02</datetime></modified>
<revised><datetime dst='true'>20060501T143234,45+02</datetime></revised>
<lastaccessed><datetime dst='true'>20060501T143234,45+02</datetime></lastaccessed>
<addedtofile><datetime dst='true'>20060430T140144,62+02</datetime></addedtofile></noteinfo>
<updatedby><name>CN=Heinz Ulrich Krause/O=Witte/C=de</name></updatedby>
<revisions><datetime dst='true'>20060430T140144,62+02</datetime><datetime
 dst='true'>20060430T140243,32+02</datetime><datetime dst='true'>20060430T140318,98+02</datetime><datetime
 dst='true'>20060430T140350,65+02</datetime><datetime dst='true'>20060430T140423,73+02</datetime><datetime
 dst='true'>20060430T144720,51+02</datetime><datetime dst='true'>20060430T153953,81+02</datetime><datetime
 dst='true'>20060430T154101,45+02</datetime><datetime dst='true'>20060430T154103,21+02</datetime><datetime
 dst='true'>20060430T154143,04+02</datetime><datetime dst='true'>20060430T154235,77+02</datetime><datetime
 dst='true'>20060430T154437,24+02</datetime><datetime dst='true'>20060430T154904,73+02</datetime><datetime
 dst='true'>20060430T155631,37+02</datetime><datetime dst='true'>20060430T160359,38+02</datetime><datetime
 dst='true'>20060430T162002,11+02</datetime><datetime dst='true'>20060430T162040,60+02</datetime><datetime
 dst='true'>20060430T162107,21+02</datetime><datetime dst='true'>20060430T163828,93+02</datetime><datetime
 dst='true'>20060501T094942,46+02</datetime><datetime dst='true'>20060501T095028,39+02</datetime><datetime
 dst='true'>20060501T101412,59+02</datetime><datetime dst='true'>20060501T104914,32+02</datetime><datetime
 dst='true'>20060501T114738,49+02</datetime><datetime dst='true'>20060501T115259,27+02</datetime></revisions>
<item name='OriginalModTime'><datetime dst='true'>20060501T143234,44+02</datetime></item>

<item name='RTONE'>
<richtext>
<pardef id='1'/>
<par def='1'>TEST</par>
<par def='1'/>
<par def='1'>&lt;&lt;RT:RTTWO&gt;&gt;</par>
<par def='1'/>
<par def='1'>noch mehr Text</par>
</richtext>
</item>


<item name='RTTWO'><richtext>
<pardef id='2'/>
<par def='2'/></richtext></item>

<item name='TextField'><text/></item>

</document>


Ich möchste gerne an fir fett markierte Stelle navigieren, um diesen Node durch einen Node aus einem anderen Dokument zu ersetzen.

Ich kann auch mit folgendem Code mein RichtextFeld ( RTONE ) im Code anspringen ( also offensichtlich das <item name="RTONE"> )

Sub Click(Source As Button)
   Dim session As NotesSession
   Dim db As NotesDatabase
   Dim inputStream As NotesStream
   
   Dim domParser As NotesDOMParser
   Dim rootElement As NotesDOMElementNode
   Dim docList As NotesDOMNodeList   
   Dim node As NotesDOMNode   
   Dim eNode As NotesDOMElementNode
   Dim i As Integer   
   
   Dim origXML As String
   origXML = "c:\RichText.xml"
   
   Set session = New NotesSession   
   Set db = session.CurrentDatabase
   
   Set inputStream = session.CreateStream
   inputStream.Open (origXML)
   
   Set domParser=session.CreateDOMParser ( inputStream )
   domParser.Process
   
   Set rootElement = domParser.Document.DocumentElement
   Set docList = rootElement.GetElementsByTagName ( "item" )
   
   If docList.NumberOfEntries = 0 Then
      Messagebox "No <item> element nodes in file", , "Error"
      Exit Sub
   End If
   
   For i = 1 To docList.NumberOfEntries
      Set node = docList.GetItem( i )
      Set enode = node
      If enode.GetAttribute("name") = "RTONE" Then
         Msgbox "found at position " & Cstr(i)
      End If
   Next
   
End Sub

Nur, wie komme ich jetzt weiter ? Wie gelange ich an die gewünschte Stelle ? Nach meiner Vorstellung müsste doch das NextChild von <item> <richtext> sein und dessen nextchild <pardef>, oder ?



Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 01.05.06 - 16:45:06
Hier einmal ein Modell, das das Einfügen über ein FindAndReplace im DXLExport in einem RichTextFeld durchführt. Danach wird das modifizierte XML wieder in das ausgewählte Dokument importiert. Es werden keine IO-Operationen im Filesystem ausgeführt.

Die Textmarke lautet #RT:RTTWO. Der Screenshot ist als Konstante im Code der Schaltfläche ExportModifyImport hinterlegt.


Code
Const REPLACE_WITH = | <picture height='71px' width='108px'><notesbitmap>
lQAmAAAAAAAAAAAAAAABAAAAAAAAAGwARwAIAAEACAACAE0ABwCWAFUIAAAAAAAAAAAAADIAQwgD
DQwLQA0AAQADDQwLQA0AAQADDQwLQA0AAQADDQwLQA0AAQADDQwLQA0AAQADDQwLQA0AAQADDQwL
yABADAEBAwMNDAvIAAEDQAwCAw0MC8gAAgMEQAsDxwEDDQwLyAACAwRACwPHAQMNDAvIAAIDBMoB
ww5ACgPCAQMNDAvIAAIDBMgBwg4BFcIAAg4VzgEEGQoXBcUBBBASChPLAQgQEhEPEBIRD0AEA8IB
Aw0MC8gAAgMExgHCDgQVOQAhwgACDhXNAQEZwgoBHMUBBAYfChPLAQgQEhEPEBIRD0AEA8IBAw0M
C8gAAgMExQECDhXCAMIhAiAhwgACDhXMAQQZJTAmxQEEIjsfE88BBBASEQ9ABAPCAQMNDAvIAAID
BMUBAg4AwiHDIAIdIcIAAg4VywEFGRdEFwXDAQUQEjIUE88BBBASEQ9ABAPCAQMNDAvIAAIDBMUB
Aj0awyDCFcIdBSEASg4VygEFGRcsKx7DAQUGKzYUE8MBASTECgETwgEIEBIRDxASEQ/EAQEjxwoB
I0ACA8UBAw0MC8gAAgMExQEFDgAOIBXCHQEVwh0EIQAVPsoBBRkXLRITwwEFIhFJFBPCAQEixgoK
EwEQEhEPEBIRD8UBASPFCgEjQAIDxgEDDQwLyAACAwTFAQEOwgACDiDCFQIdFcIdAyEOL8oBEhkX
BSIRDwEQEiYWFBMBFhQXBcIBDBYUEQ8QEhEPEBIRD8YBASPDCgEjQAIDxwEDDQwLyAACAwTFAQEO
wwACDiDCFcIdwg4COC/KAQ0ZFwUkJR4BBh8cFhQTxQECEBLCCgoRDxASEQ8QEhEPxwEDIwojQAMD
Aw0MC8gAAgMExQEBDsIABRoADiAdwg7CAAI4DsoBDRkXBRYUEwEiFwUWFBPCAQIGH8UKChEPEBIR
DxASEQ/IAQEjQAMDAQEDDQwLyAACAwTFAQQOACoawgAEPA4AGsIAAicOygEQGRcFARkRDxkmARYU
EwEWFMIKDhMBFhQRDxASEQ8QEhEPQAQDwgEDDQwLyAACAwTFAQQOABoqxQAFGioAJw7KAREZFwUB
JCU2FBwBFhQTASQKHMMBDBYUEQ8QEhEPEBIRD0AEA8IBAw0MC8gAAgMExQEDDgAaxgAHKhoAJw4a
FcgBERkXBQEWFEIXBQEWFBMBJAomwgENFhQKEQ8QEhEPEBIRD0AEA8IBAw0MC8gAAgMExQEBGsMO
BBoVS0zCAAQaACcOwhrIAQMZFwXCAQMZCibCAQYWFBMBFhTGCgoXBRASEQ8QEhEPQAQDwgEDDQwL
yAACAwTJAQIVGsIOCBoVORonDhoVyAEDGRcFwgEDIgocwgEDFhQTwgECFhTDCgwcGSUeEBIRDxAS
EQ9ABAPCAQMNDAvIAAIDBM0BAhUaww4CGhVACQPDAQMNDAvIAAIDBEALA8cBAw0MC8gAAgMEQAsD
xwEDDQwLyAACAwRACwPHAQMNDAvIAAIDBEALA8cBAw0MC8gAAgMEQAsDxwEDDQwLyAACAwRACwPH
AQMNDAvIAAIDBEALA8cBAw0MC8gAAgMExQEJEBIKEwYILSkeyAEDBggFwwEDBggFxwEDBggFzwED
BggFwwEGBggFBggFxAEDBggFxgEDBggFxwEEBggFAQMNDAvIAAIDBMUBAwYIBc4BAwYIBcMBAwYI
BUADAwQBBggFwwEGBggFBggFzQEDBggFxwEEBggFAQMNDAvIAAIDBMUBDxQKJUUIBQEGCAUGMTUX
BcIBAwYIBcMBEAYIBQEWFAoXBQEGCAUGKEPCCgMcARnDCgEmwwEDBggFwwEWBggFBggFBjE1FywI
BQEWFAolHgYIQcIKARzEAQQGCAUQAw0MC8gAAgMExQENBggFBggFAQYIBQYfHMQBAwYIBcMBFAYI
BRASEwEkEQ8GCAUGHxMBJBEPwgEDECkewwEDBggFwwEaBggFBggFBh8cAQYIBRASHAEkEUgfEwEk
EQ/DAQQGCC0SAw0MC8gAAgMExQENBggFBggFAQYIBQYIBcQBAgYfxQoTFwUGCAUBECkeBggFBggF
AQYIBcIBAiITxAEDBggFwwEQBggFBggFBggFAQYIBQYIBcMBBwYIBQEGCAXDAQQGKzAKAw0MC8gA
AgMExQENBggFBggFAQYIBQYIBcQBAwYIBcMBBQYIBQYfwwoQJR4GCAUGCAUBBggFAQYoD8QBAwYI
BcMBEAYIBQYIBQYIBQEGCAUGKA/DAQcGCAUBBggFwwEEBh8TFgMNDAvIAAIDBMUBDQYIBQYIBQEG
CAUGCAXEAQMGCAXDAQYGCAUGCAXEAQ0GCAUGCAUBBggFECkexQEDFjQewwEQBigPBggFBggFAQYI
BQYIBcMBBwYIBQEGCAXDAQQGCAUBAw0MC8gAAgMExQENBggFFjQeASIXBQYIBcQBAwYIBcMBFgYI
BRASEwEGCAUGCAUGCAUBBggFIhPHAQIZJsIBGxASEwEGCAUGCAUBBggFEBIcAQYILAgFAQYIBcMB
BAYIBQEDDQwLyAACAwTFAQUGCAUBIsIKBjJABQYIBcQBAwYIBcMBBgYIBQEWFMIKDRwBBggFBggF
AQYIRxTECgETxAEBGcMKARPCARcGCAUGCAUBBggFARYUCiUeBggFAQYIBcMBBAYIBQEDDQwLyAAC
AwRACwPHAQMNDAvIAAIDBEALA8cBAw0MC8gAAgMEQAsDxwEDDQwLyAADAwQBQAsExgcDDQwLyAAE
AwQBB0ALAcUDAw0MC8gABQMEAQcDQAsFxAkDDQwLyAAGAwQBBwMJQAsAwwADDQwLyAAGAwQBBwMJ
QAsAwwCWANkBAAAAAAAAAAAAABUAxwEDDQwLyAAGAwQBBwMJQAsAwwADDQwLyAAGAwQBBwMJQAsA
wwADDQwLyAAGAwQBBwMJQAsAwwADDQwLyAAGAwQBBwMJQAsAwwADDQwLyAAGAwQBBwMJQAsAwwAD
DQwLyAAGAwQBBwMJQAsAwwADDQwLyAAGAwQBBwMJQAsAwwADDQwLyAAGAwQBBwMJQAsAwwADDQwL
yAAGAwQBBwMJQAsAwwADDQwLyAAGAwQBBwMJQAsAwwADDQwLyAAGAwQBBwMJQAsAwwADDQwLyAAG
AwQBBwMJQAsAwwADDQwLyAAGAwQBBwMJQAsAwwADDQwLyAAGAwQBBwMJQAsAwwADDQwLyAAEAwQB
B0ADBsYCxBhABwbDAgMNDAvIAAQDBAEHQAMGxgIEGAAbGEAHBsMCAw0MC8gABAMEAQdAAwbGAgQY
ABsYQAcGwwIDDQwLyAAEAwQBB0ADBsYCBBgAGxhABwbDAgMNDAvIAAQDBAEHQAMGwwLEGAIAG8QY
QAcGAw0MC8gABAMEAQdAAwbDAgEYwwDFGwEYywICLj/EDgU6Ri4zN0AEBsICAw0MC8gABAMEAQdA
AwbDAgIOGMYbARjMAgMuMzdABQbCApcA7QAAAP///6jA0NDY6HCYwKjA2HDA0KioqKC4yBhAmODg
4ABAgHBoYJiYoMjI0AAAAIjA0KjAyABQqFBQgBiAyDhAgHCgyKjAuABAmDAwMHBogECAuPjgsDiQ
0NDg6FCo0BhAgJi42CBAWIiAiABgyKiQmABAiABouKjI4BhQqFBQiLjQ4BhAiHCoqHDAyNC4cAgQ
GBhQgBhQmBiAqCAASDhAiDhQgFCouIjY6KjA4ODo8AAAKABQiAgYIBAgMBgwSCAAADhAmDhogDho
mFBogFCAiFCQqGi46HDAuIioqIjAuNjo8Ojw+PDw+JgArgAAAAAAAAAAAAAAAAABAAQAAgAEAAAA
AAAAAAMDAwMDAwMDAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAEBAQEB
AQEBAAAAAAAAAAAAAAAAAAAAAAcHBwcHBwcHAAD+/wAAAAAAAAAAAAAAAAkJCQkJCQkJAAAAAAAA
AAAAAAAAAAAAAAICAgICAgICAAAAAAAAAACWPgAAAAAAAA==
</notesbitmap></picture> |

Code
Sub Click(Source As Button)
	Dim session As New NotesSession
	Dim db As NotesDatabase
	Set db = session.CurrentDatabase
	
	Dim dc As NotesDocumentCollection
	Set dc = db.UnprocessedDocuments
	If dc.Count = 0 Then
		Messagebox "No document selected",, "No document"
		Exit Sub
	End If
	Dim doc As NotesDocument
	Set doc = dc.GetFirstDocument
	
	Dim NewDoc As NotesDocument
	Dim rtitem As NotesRichTextItem
	Set InMemDoc = db.CreateDocument
	Set rtitem = InMemDoc.CreateRichTextItem( "DXL" )
	
	' Export DXL int RichTextField 
	Dim exporter As NotesDXLExporter
	Set exporter = session.CreateDXLExporter
	Call exporter.SetInput(doc)
	Call exporter.SetOutput(rtitem)
	Call exporter.Process
	
	' Modify Body with FindAndReplace
	' #RT:RTTWO
	Dim rtnav As NotesRichTextNavigator
	Dim rtrange As NotesRichTextRange
	Dim ret As Integer
	Set rtnav = rtItem.CreateNavigator
	Set rtrange = rtItem.CreateRange
	
	ret =  rtrange.FindAndReplace _
	( "#RT:RTTWO",_ ' find 
	REPLACE_WITH, _ ' replaceWith
	RT_REPL_ALL + RT_FIND_CASEINSENSITIVE) 
	
	Call rtItem.Update ' Must update before looping
	
	Dim importer As NotesDXLImporter
	Set importer = session.CreateDXLImporter(rtItem, db)
	importer.DocumentImportOption = DXLIMPORTOPTION_REPLACE_ELSE_IGNORE
	Call importer.Process
	Call InMemDoc.remove(True)
	'doc.form = "Memo"
	'doc.SendTo = "Heinz Ulrich Krause/witte/de"
	'Call doc.Send(False)
End Sub

Anbei noch einmal eine aktuelle Sample Database
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 01.05.06 - 18:15:29
Abschließend für heute bleibt noch, daß die DXLImport und DXLExport class mit richtig großen Datenmengen ( > 100 MB ) gut klarkommt. Das FindAndReplace steigt aber bei diesen Datenmengen mit einem RSOD aus ...  :P
Da ist schon bei einem kleinen Attachment ( 1MB ) im SourceDoc Schluß
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 01.05.06 - 18:35:55
Dieser Code funktioniert bei mir mit einem Dokument mit einem Anhang > 300 MB ohne RSOD; allerdings wird hier auch nichts ersetzt, sondern lediglich die Position des RichTextFeldes im XML gefunden. Immerhin aber schon mal ein Anfang  ;D

Zitat
Sub Click(Source As Button)
   
   Dim rootElement As NotesDOMElementNode
   Dim docList As NotesDOMNodeList   
   Dim node As NotesDOMNode   
   Dim eNode As NotesDOMElementNode
   Dim i As Integer   
   
   Dim session As New NotesSession
   Dim db As NotesDatabase
   Set db = session.CurrentDatabase
   
   Dim dc As NotesDocumentCollection
   Set dc = db.UnprocessedDocuments
   If dc.Count = 0 Then
      Messagebox "No document selected",, "No document"
      Exit Sub
   End If
   Dim doc As NotesDocument
   Set doc = dc.GetFirstDocument
   
   Dim NewDoc As NotesDocument
   Dim rtitem As NotesRichTextItem
   Set InMemDoc = db.CreateDocument
   Set rtitem = InMemDoc.CreateRichTextItem( "DXL" )
   
   ' Export DXL int RichTextField
   Dim exporter As NotesDXLExporter
   Set exporter = session.CreateDXLExporter
   Call exporter.SetInput(doc)
   Call exporter.SetOutput(rtitem)
   Call exporter.Process
   
   Msgbox "ready"
   
   Dim domParser As NotesDOMParser
   Set domParser=session.CreateDOMParser ( rtItem )
   domParser.Process
   Set rootElement = domParser.Document.DocumentElement
   Set docList = rootElement.GetElementsByTagName ( "item" )
   
   If docList.NumberOfEntries = 0 Then
      Messagebox "No <item> element nodes in file", , "Error"
      Exit Sub
   End If
   
   For i = 1 To docList.NumberOfEntries
      Set node = docList.GetItem( i )
      Set enode = node
      If enode.GetAttribute("name") = "RTONE" Then
         Msgbox "found at position " & Cstr(i)
      End If
   Next
   
%REM   
   ' Modify Body with FindAndReplace
   ' #RT:RTTWO
   Dim rtnav As NotesRichTextNavigator
   Dim rtrange As NotesRichTextRange
   Dim ret As Long
   Set rtnav = rtItem.CreateNavigator
   Set rtrange = rtItem.CreateRange
   
   ret =  rtrange.FindAndReplace _
   ( "#RT:RTTWO",_ ' find
   REPLACE_WITH, _ ' replaceWith
   RT_REPL_ALL + RT_FIND_CASEINSENSITIVE)
   
   Call rtItem.Update ' Must update before looping
   
%END REM   
   Dim importer As NotesDXLImporter
   Set importer = session.CreateDXLImporter(rtItem, db)
   importer.DocumentImportOption = DXLIMPORTOPTION_REPLACE_ELSE_IGNORE
   Call importer.Process
   'Call InMemDoc.remove(True)
   Msgbox "Import ready"   
End Sub

Wenn ich es mir so recht überlege, sind mit DXL auch so Sachen möglich, wie : " Wann wurde ein Dokument von wem gelesen?", ohne daß der Lesende Autorenrechte auf das Dokument hat, solange der Code per Agent über den Server ausgeführt wird.

<offtopic> Irgendwie scheint so kein anderer in das Thema mit einsteigen zu wollen, gell ? </offtopic>
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: koehlerbv am 01.05.06 - 19:39:20
<offtopic> Irgendwie scheint so kein anderer in das Thema mit einsteigen zu wollen, gell ? </offtopic>

Oh doch, aber die Zeit dazu muss da sein: Mich interessiert das extrem, aber ich komme frühestens dazu, wenn ich wieder aus Italien zurück bin (> 20.05.2006).

Bernhard
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: flaite am 01.05.06 - 19:50:05
Ich schaus mir auf jeden Fall gleich mal an.
Soll ich vielleicht als frisch wieder-"erweckter" (haha) Linux User darüber weinen, dass Notes keinen vernünftigen Linux Client hat  ;D
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: flaite am 01.05.06 - 20:41:40
Erstmal zum navigieren:
Ich habs mit dem oberen Skript gemacht (griff auf ein File zu und erschien mir einfacher):

Code
Sub Initialize
	Dim session As NotesSession
	Dim db As NotesDatabase
	Dim inputStream As NotesStream
	
	Dim domParser As NotesDOMParser
	Dim rootElement As NotesDOMElementNode
	Dim docList As NotesDOMNodeList   
	Dim node As NotesDOMNode   
	Dim nodeChildOfRTOne As NotesDOMNode	
	Dim eNode As NotesDOMElementNode
	Dim i As Integer   
	
	Dim origXML As String
	origXML = "c:\temp\RichText.xml"
	
	Set session = New NotesSession   
	Set db = session.CurrentDatabase
	
	Set inputStream = session.CreateStream
	inputStream.Open (origXML)
	
	Set domParser=session.CreateDOMParser ( inputStream )
	domParser.Process
	
	Set rootElement = domParser.Document.DocumentElement
	Set docList = rootElement.GetElementsByTagName ( "item" )
	
	If docList.NumberOfEntries = 0 Then
		Messagebox "No <item> element nodes in file", , "Error"
		Exit Sub
	End If
	
	For i = 1 To docList.NumberOfEntries
		Set node = docList.GetItem( i )
		Set enode = node
		If enode.GetAttribute("name") = "RTONE" Then
			Msgbox "found at position " & Cstr(i)
			Stop
rem hier kommen ein paar ergänzungen....
			If enode.hasChildNodes Then
				
				Set nodeChildOfRTOne = enode.FirstChild
				While Not (nodeChildOfRTOne.isNull)
					Msgbox nodeChildOfRTOne.NodeName & " vom Typ : " & Cstr(nodeChildOfRTOne.NodeType)
					
					Set nodeChildOfRTOne = nodeChildOfRTOne.nextSibling
				Wend
				
				
			End If
		End If
	Next
End Sub

... und jetzt willst du da noch eine node anhängen? Versuch mal, ob ich aus dem bisherigen Text i.S. von ToDo schlau werde.

DOM hat als api in jeden Fall ein paar bekannte Überraschungen. Z.B. dass der Text-Nodes als Childnodes von enode rausgibt ist nicht direkt offensichtlich.
Beim Erzeugen und Einhängen von nodes gab es aber auch gotchas. Ich sollte die aber kennen.
In Java benutzt man heute übrigens eher neuere apis oberhalb von dom die einfacher in der Handhabung sind, wie z.B. dom4j.
Dom ist eine xml Api für allemöglichen Programmiersprachen. Durch diesen kleinste-gemeinsame-Nenner Ansatz wird die api selbst natürlich kompliziert.
Die Api ist entkoppelt von der Programmiersprache. Das hat eben auch Nachteile :-)
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: flaite am 01.05.06 - 22:07:44
Hab das nochmal kurz ein bischen erweitert.
Er überprüft jetzt auch childs von <richtext>
Sicher vom code her nicht das gelbe. Man sollte das irgendwie rekursiver und vielleicht auch wiederverwendbarer machen. Jedenfalls iteriert er jetzt über die pars, pardefs oder wie immer die heissen.

Allgemein gute Ideen:
Mit der Superklasse NotesDomNode arbeiten. Diese gehört einer von 13 Typen an (s. Attribut NodeType).
In dieser Klasse gibts btw. auch Methoden zum anhängen (nur am Ende einer Liste -> outch), ersetzen und entfernen.

Beim Erstellen einer Node gibts einen Trick.  Unwahrscheinlich, dass ich das heute abend noch packe.

Hier nur noch ein Teil des obigen Skripts. den block einfach austauschen.

Code
oben in den dims: Dim nodeChildRichText As NotesDOMNode
If enode.GetAttribute("name") = "RTONE" Then
			Msgbox "found at position " & Cstr(i)
			Stop
			If enode.hasChildNodes Then
				
				Set nodeChildOfRTOne = enode.FirstChild
				While Not (nodeChildOfRTOne.isNull)
					Msgbox nodeChildOfRTOne.NodeName & " vom Typ : " & Cstr(nodeChildOfRTOne.NodeType) 
					If nodeChildOfRTOne.NodeName = "richtext" Then 
						If nodeChildOfRtOne.hasChildNodes Then 
							Set  nodeChildRichText = nodeChildOfRTOne.FirstChild
							While Not (nodeChildRichText.IsNull) 
								Msgbox "kind von <richtext>:" & nodeChildRichText.nodeName & " vom Typ: " & Cstr(nodeChildRichText.NodeType) 
								
								Set nodeChildRichText = nodeChildRichText.nextSibling 
								
							Wend
						End If
						
						
					End If
					Set nodeChildOfRTOne = nodeChildOfRTOne.nextSibling
				Wend
				
				
			End If
		End If

Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: flaite am 02.05.06 - 08:46:34
Frage: Ist das irgendwie hilfreich oder nicht?
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 02.05.06 - 08:57:14
Hallo Axel, ja, das hilft schon ein Stück weiter. Zumindest komme ich jetzt an die <par ... > nodes ran.
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: flaite am 02.05.06 - 11:58:55
Ein nächster Schritt wäre dann dies:
Code
Set notesDOMNode = notesDOMNode.ReplaceChild( newChild, oldChild )
Dazwischen mußt du aber die newChild erst noch erzeugen.

Für die Erzeugung von Nodes hat die Klasse:
NotesDOMDocumentNode class
createMethoden (Factory-method).
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 02.05.06 - 15:24:34
So, hier erst einmal der Code, um die Einfügemarke RT:RTONE im RichtextFeld RTONE zu finden

Code
Sub Click(Source As Button)
	
	Dim session As NotesSession
	Dim db As NotesDatabase
	Dim inputStream As NotesStream
	
	Dim domParser As NotesDOMParser
	Dim rootElement As NotesDOMElementNode
	Dim docList As NotesDOMNodeList   
	Dim node As NotesDOMNode   
	Dim nodeChildOfRTOne As NotesDOMNode
	Dim nodeChildRichText As NotesDOMNode
	
	Dim eNode As NotesDOMElementNode
	Dim parNode As NotesDOMElementNode
	Dim i As Integer   
	
	Dim origXML As String
	origXML = "c:\RichText.xml"
	
	Set session = New NotesSession   
	Set db = session.CurrentDatabase
	
	Set inputStream = session.CreateStream
	inputStream.Open (origXML)
	
	Set domParser=session.CreateDOMParser ( inputStream )
	domParser.Process
	
	Set rootElement = domParser.Document.DocumentElement
	Set docList = rootElement.GetElementsByTagName ( "item" )
	
	If docList.NumberOfEntries = 0 Then
		Messagebox "No <item> element nodes in file", , "Error"
		Exit Sub
	End If
	
	For i = 1 To docList.NumberOfEntries
		Set node = docList.GetItem( i )
		Set enode = node
		If enode.GetAttribute("name") = "RTONE" Then
			'Msgbox "found at position " & Cstr(i)
			
			If enode.hasChildNodes Then
				
				Set nodeChildOfRTOne = enode.FirstChild
				While Not (nodeChildOfRTOne.isNull)
					'Msgbox nodeChildOfRTOne.NodeName & " vom Typ : " & Cstr(nodeChildOfRTOne.NodeType)
					If nodeChildOfRTOne.NodeName = "richtext" Then
						If nodeChildOfRtOne.hasChildNodes Then
							Set  nodeChildRichText = nodeChildOfRTOne.FirstChild
							While Not (nodeChildRichText.IsNull)
								'Msgbox "kind von <richtext>:" & nodeChildRichText.nodeName & " vom Typ: " & Cstr(nodeChildRichText.NodeType)
								If nodeChildRichText.NodeName = "par" Then
									'Msgbox nodeChildRichText.NodeName
									Set parnode = nodeChildRichText
									If ( Not parNode.FirstChild.IsNull ) Then
										If ( Not Isnull (parnode.FirstChild.NodeValue ) ) Then
											If parnode.FirstChild.NodeValue = "RT:RTONE" Then
												Msgbox "HEUREKA"
											End If
										End If
										
									End If
									
								End If
								
								Set nodeChildRichText = nodeChildRichText.nextSibling
								
							Wend
						End If
						
						
					End If
					Set nodeChildOfRTOne = nodeChildOfRTOne.nextSibling
				Wend
			End If
		End If
	Next
	
End Sub


Funktioniert auch bei einer XML Datei mit 10MB in knapp einer Sekunde. Ist also für eine Hintergrundaktion genügend performant, denke ich ...

Der Code müsste auch verwendbar sein, um die <par ... > Nodes des RT Feldes auszulesen, dessen Werte eingefügt werden sollen.
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: flaite am 02.05.06 - 15:48:15
Man sollte das deutlich schöner machen können.
Ich werds versuchen. Hier traue ich Thomas Völk übrigens gute Vorschläge zu  ;)
Aber erst einmal die Funktionalität durchprogrammieren.
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 02.05.06 - 16:03:54
Mir geht es momentan auch erst einmal darum, die nötigen Funktionen zusammenzubekommen. "Schön machen" kann man das dann immer noch.  :D
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: animate am 02.05.06 - 18:16:13
Mein erster Vorschlag wäre, einen anderen Parser zu nehmen. Der NotesDOMParser kann sehr wenig, wenn ich das noch richtig in Erinnerung habe. Andere Parser unterstützen z. B. XPath-Anweisungen, mit denen du dir die Schleife über alle Knoten sparen kannst, um einen oder mehrere bestimmte zu finden. Das würde allerdings bedeuten, dass du das in Java machen müsstest.
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: Thomas Schulte am 02.05.06 - 18:38:58
Das entscheidende an dem Teil ist, das es mit Notes native funktionieren muss. Und das ohne noch irgendwas zusätzlich zu installieren.
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: flaite am 02.05.06 - 20:32:50
Versuchen wir es erst einmal mit den Notes libraries. Vielleicht bekäme man dom4j (mein Favorit) oder ähnliches in domino 7 ans laufen. Aber dann vielleicht wieder nicht als an den Agenten angehängtes jar sondern nur im lib Verzeichnis. Und wenn das auf userworkstations laufen soll, dann müßte man das erst einmal verteilen...
In Notes 6 (Name dieses Forums) kann man das vermutlich eh vergessen, da erst mit Notes 7 ein JAXP kompatibler xml parser überhaupt in notes Java eingeführt wurde. 
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: flaite am 02.05.06 - 20:38:50
hab ich eben über google gefunden.
Rocky Oliver ist mein 2.-Lieblings-Loti. Hinter Bob Balaban.
http://www.lotusgeek.com/SapphireOak/LotusGeekBlog.nsf/d6plinks/ROLR-6CPL56
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: flaite am 02.05.06 - 20:52:02
Hilft dieser Stan Rogers code weiter:
Oder vielleicht wendest du dich einfach an ihn. Normal gibt der sich ja sehr hilfsbereit (ich glaub 60% der Antworten zu Programmierfragen in Notes-Foren sind von ihm). Ansonsten kann ich auch weitermachen. Hab aber z.Zt. ziemlich viel anderen Kram.

Code
Function CrossDocClone(SourceNode As NotesDOMNode, TargetParentNode As NotesDOMNode) As NotesDOMNode

Dim NewNode As NotesDOMNode
Dim NewChildNode As NotesDOMNode
Dim NextNode As NotesDOMNode
<error handling statement goes here -- there may be failures>

%REM
This assumes the following objects are Global
SourceRootDoc -- the NotesDOMDocumentNode that clones are drawn from
TargetRootDoc -- the NotesDOMDocumentNode that clones are inserted into
%END REM

Select Case SourceNode.NodeType
'ignoring attribute, comment, document and entity types
Case DOMNODETYPE_ELEMENT_NODE
Set NewNode = TargetRootDoc.CreateElementNode(SourceNode.NodeName)
Case DOMNODETYPE_TEXT_NODE
Set NewNode = TargetRootDoc.CreateTextNode(SourceNode.NodeValue)
Case DOMNODETYPE_CDATASECTION_NODE
Set NewNode = TargetRootDoc.CreateCDATASectionNode(SourceNode.NodeValue)
End Select
If SourceNode.HasAttributes Then
Dim map As NotesDOMNamedNodeMap
Dim attrib As NotesDOMAttributeNode
Dim count As Integer
Set map = SourceNode.Attributes
For count = 1 To map.NumberOfElements
Set attrib = map.GetItem(count)
Call NewNode.SetAttribute(attrib.NodeName, attrib.NodeValue)
Next
End If
Call TargetParentNode.AppendChild(NewNode)

If SourceNode.HasChildNodes Then
Set NextNode = SourceNode.FirstChild
Set NewChildNode = CrossDocClone(NextNode, NewNode)
Set NextNode = NextNode.NextSibling
While Not NextNode.IsNull
Set NewChildNode = CrossDocClone(NextNode, NewNode)
Wend
End If
End Function
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: flaite am 03.05.06 - 06:25:38
Ein Weg, um eine Node zu erzeugen (und in eine vorhandene DOM-Repräsentation eines xml-Dokuments einzuhängen) sieht wie folgt aus:

1. DomDocumentNode-Objekt erzeugen:
Code
Dim docNode As NotesDOMDocumentNode
[...]
Set docNode = domParser.Document	

2. Mit docNode (!) eine DomElement erzeugen.
Code
Dim newNode as notesDOMElementNode
[...]
Set newNode = docNode.CreateElementNode("NewElement")
docNode repräsentiert das im Parser aktive (spelling?) xml-Document
Dies erzeugt ein <newElement></newElement> (Attribute, childNodes als Text oder als weitere nodes können da sicher angefügt werden).

3. newNode an eine existierende node anhängen:
Code
Call nodeChildRichText.AppendChild(newNode)

Der entsprechende code in meinem Beispielcode sieht so aus:
Code
 
If nodeChildRichText.NodeName = "pardef" Then 
Stop
Set newNode = docNode.CreateElementNode("NewElement")
Call nodeChildRichText.AppendChild(newNode)
End If
Aber wie hängt man jetzt eine Node aus einem anderen xml Dokument ein?
Man kann alle Bestandteile dieser Node auslesen (nodeName, enthaltener Text, enthaltene Nodes, Attribute-Nodes) und daraus eine neue Node erzeugen. Aber vielleicht gibts einen besseren Weg.


Aus
Code
<item name='RTTWO'><richtext>
<pardef id='2'/>
<par def='2'/></richtext></item>
wird wohl:
Code
<item name='RTTWO'><richtext>
<pardef id='2'>
<newElement/>
</pardef>
<par def='2'/></richtext></item>
Nicht was du wolltest, aber vielleicht ein Starter.

Ich hab auch Probleme das manipulierte xml in eine Datei herauszuschreiben. Kann mir da jemand helfen?

Axel
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 03.05.06 - 07:19:30
Zitat
Ich hab auch Probleme das manipulierte xml in eine Datei herauszuschreiben. Kann mir da jemand helfen?

Ich mache das vielleicht ein wenig umständlich, aber so bekomme ich das hin.

ich DXL - exporte das doc in ein RTITEM, mache dort die Manipulationen. Anschließend DXL - importe ich die Änderungen wieder in das doc und streame dann einen DXLExport in eine Datei.  ::) :P

Den Code von Rocky habe ich auch schon gesehen, aber noch nicht richtig verstanden.

Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: flaite am 03.05.06 - 07:26:07
Jedenfalls kannst du mit meinem code mal versuchen, dort irgendwo eine neue node einzuhängen?
Oder kannst du mir deinen code schicken, damit ich das damit mal versuchen kann. Wenn es eine kleine Test.nsf ist, geht es ja.
appendChild funktioniert jedenfalls. Und da gibts noch replaceChild.

Gruß Axel
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 03.05.06 - 07:28:49
kann ich dir frühestens heute abend schicken; heute ist wieder Grosskampftag in der Firma ( Helpdesk Schulung *grins* )
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 03.05.06 - 07:38:09
Axel: du kannst aber auch direkt in eine Datei streamen. Da brachst du dann einen outputStream, . Dem DOMParser teilst du dann diesen output mit setOutput ( stream ) mit.

Das mit dem RTITEM habe ich deshalb gemacht, damit ich mir die Änderungen direkt im Dokument ansehen kann.

Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: animate am 03.05.06 - 08:31:46
Das Zauberwort heißt Pipelining (http://www-12.lotus.com/ldd/doc/domino_notes/Rnext/help6_designer.nsf/f4b82fbb75e942a6852566ac0037f284/6b697e2edf47507885256c54004ba771?OpenDocument#217111513629501461). Wenn du das verstanden hast ist alles ganz einfach :)

Zitat von hier (http://www-128.ibm.com/developerworks/lotus/library/ls-LS_XML1/index.html)
Zitat
Pipelining works because the XML processors require you to identify input and output before you call the Process method on the first object in the line. The simplest way to set up a pipeline is to specify the inputs for all the processes, but no outputs except for the output of the last process in the line.

Und von hier (http://www-10.lotus.com/ldd/nd6forum.nsf/55c38d716d632d9b8525689b005ba1c0/c93412d9d0b01b3f80256e54004c4b2d?OpenDocument&Highlight=0,pipelining).
Zitat
The whole point of a pipeline is that it all runs at the same time. It does not process each stage separately. Set the pipleine up, then call Process on the first stage in the pipeline. Do not call Process on the other stages. The first stage pushes the data through all the stages that you have set up.
Beiträge im Forum von diesem Rod Whiteley zum Thema DXL kann ich nur empfehlen. Die haben mir immer sehr geholfen.
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 03.05.06 - 08:33:35
Stümmt, bin auch auch gerade drauf gestossen  ::)
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 03.05.06 - 19:24:23
*HaareRauf* Gerade, als ich dachte, ich hätte das Pipelining verstanden, .... bin ich so schlau als wie zuvor .

Der Exporter übergibt an den Parser, der Parser parsed, übergibt aber nicht an den Importer ( so sieht es zumindest aus ) Der Code läuft fehkerfrei durch. Im Debugger sieht man auch, daß

Zitat
parnode.FirstChild.NodeValue = "Hallo Welt"

gesetzt wird. Also müsst edoch das Document aktualisiert werden.  ???

Das ist das "Dumme" beim Pipeline; man sieht irgendwie nicht mehr, was passiert ...

Code
Sub Click(Source As Button)
	
	Dim session As New NotesSession
	Dim db As NotesDatabase
	Set db = session.CurrentDatabase
	
	Dim rootElement As NotesDOMElementNode
	Dim docList As NotesDOMNodeList   
	Dim node As NotesDOMNode   
	Dim nodeChildOfRTOne As NotesDOMNode
	Dim nodeChildRichText As NotesDOMNode
	
	Dim eNode As NotesDOMElementNode
	Dim parNode As NotesDOMElementNode
	Dim cloneNode As NotesDOMNode   
	Dim i As Integer   
	
	Dim dc As NotesDocumentCollection
	Set dc = db.UnprocessedDocuments
	If dc.Count = 0 Then
		Messagebox "No document selected",, "No document"
		Exit Sub
	End If
	Dim doc As NotesDocument
	Set doc = dc.GetFirstDocument
	
	Dim exporter As NotesDXLExporter
	Dim domParser As NotesDOMParser
	
	Set exporter = session.CreateDXLExporter
	Set domParser=session.CreateDOMParser 
	
	Call exporter.SetInput ( doc )
	Call exporter.SetOutput ( domParser )
	Call exporter.process
	
	Set rootElement = domParser.Document.DocumentElement
	Set docList = rootElement.GetElementsByTagName ( "item" )
	
	If docList.NumberOfEntries = 0 Then :	Exit Sub
	
	For i = 1 To docList.NumberOfEntries
		Set node = docList.GetItem( i )
		Set enode = node
		If enode.GetAttribute("name") = "RTONE" Then
			If enode.hasChildNodes Then
				Set nodeChildOfRTOne = enode.FirstChild
				While Not (nodeChildOfRTOne.isNull)
					If nodeChildOfRTOne.NodeName = "richtext" Then
						If nodeChildOfRtOne.hasChildNodes Then
							Set  nodeChildRichText = nodeChildOfRTOne.FirstChild
							While Not (nodeChildRichText.IsNull)
								If nodeChildRichText.NodeName = "par" Then
									Set parnode = nodeChildRichText
									If ( Not parNode.FirstChild.IsNull ) Then ' skip NULL Values
										If parnode.FirstChild.NodeValue = "RT:RTONE" Then
											parnode.FirstChild.NodeValue = "Hallo Welt"
											Msgbox "HEUREKA"
										Else
										End If
									End If
								End If
								Set nodeChildRichText = nodeChildRichText.nextSibling
							Wend
						End If
					End If
					Set nodeChildOfRTOne = nodeChildOfRTOne.nextSibling
				Wend
			End If
		End If
	Next
	
	
	Dim importer As  NotesDXLImporter
	Set importer = session.CreateDXLImporter
	Call importer.SetInput ( domParser )
	Call importer.SetOutput ( db )
	
End Sub
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 03.05.06 - 21:06:11
Habe es mal ins LDD gepostet und, wie erhofft, eine Antwort von Stan Rogers erhalten.

https://www-10.lotus.com/ldd/nd6forum.nsf/DateAllThreadedweb/024f2d5bde011f06852571630063abaf?OpenDocument
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: flaite am 03.05.06 - 21:58:49
Klasse. Ich hab mir auch jetzt ein bischen die Zähne ausgebissen.
Bin aber auch müde. Der hat auf jeden Fall etwas verstanden das ich nicht sehe.
Interessant.

bleib dran
Axel
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: flaite am 03.05.06 - 22:29:53
Sind in dem auf notes.net geposteten code Exporter/Importer auch NotesDOMParser Objekte?
Das glaub ich.
Kriegs aber z.Zt. nicht hin.
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: flaite am 03.05.06 - 23:08:48
Nö. Leider immer noch nicht.

Agent:

Options:
Code
Option Public
Option Declare

Declarations:
Code
Dim session As NotesSession

Initialize:
Code
Dim db As NotesDatabase
	Dim inputStream As NotesStream
	
	
	Dim docNode As NotesDOMDocumentNode
	Dim domParser As NotesDOMParser
	
	Dim Importer As NotesDOMParser
	Dim rootElement As NotesDOMElementNode
	Dim docList As NotesDOMNodeList   
	Dim node As NotesDOMNode   
	Dim newNode As NotesDOMNode
	Dim nodeChildOfRTOne As NotesDOMNode	
	Dim nodeChildRichText As NotesDOMNode
	
	Dim eNode As NotesDOMElementNode
	Dim i As Integer   
	
	Dim origXML As String
	Dim outputFile As String	
	Dim outputStream As NotesStream
	Dim exporter As NotesDOMParser
	
	
	
	origXML = "c:\temp\RichText.xml"
	
	Set session = New NotesSession   
	Set db = session.CurrentDatabase
	
	Set inputStream = session.CreateStream
	
	inputStream.Open (origXML)
	
	
	Set exporter=session.CreateDOMParser ()	
	Set domParser = session.CreateDOMParser()
	Set Importer=session.CreateDOMParser ( inputStream)
	
	outputFile = "c:\temp\RichTextNew.xml"	
	Set outputStream = session.CreateStream	
	outputStream.Open(outputFile)
'	Set input for Exporter
'Set output for Exporter
'Set output for Parser
	Call exporter.setInput(domParser)
	Call exporter.setOutput(outputStream)
	Call domParser.setInput(importer)
	
	
	
	
	importer.Process
	On Event PostDOMParse From domParser Call PlayWithDXLRoutine	
	
	Set docNode = domParser.Document	
	Set rootElement = domParser.Document.DocumentElement
	Set docList = rootElement.GetElementsByTagName ( "item" )
	
	If docList.NumberOfEntries = 0 Then
		Messagebox "No <item> element nodes in file", , "Error"
		Exit Sub
	End If
	
	For i = 1 To docList.NumberOfEntries
		Set node = docList.GetItem( i )
		Set enode = node
		If enode.GetAttribute("name") = "RTONE" Then
			Msgbox "found at position " & Cstr(i)
			Stop
			If enode.hasChildNodes Then
				
				Set nodeChildOfRTOne = enode.FirstChild
				While Not (nodeChildOfRTOne.isNull)
					Msgbox nodeChildOfRTOne.NodeName & " vom Typ : " & Cstr(nodeChildOfRTOne.NodeType) 
					If nodeChildOfRTOne.NodeName = "richtext" Then 
						If nodeChildOfRtOne.hasChildNodes Then 
							Set  nodeChildRichText = nodeChildOfRTOne.FirstChild
							While Not (nodeChildRichText.IsNull) 
								'Msgbox "kind von <richtext>:" & nodeChildRichText.nodeName & " vom Typ: " & Cstr(nodeChildRichText.NodeType) 
								If nodeChildRichText.NodeName = "pardef" Then 
									Stop
									Set newNode = docNode.CreateElementNode("NewElement")
									Call nodeChildRichText.AppendChild(newNode)
								End If
								Set nodeChildRichText = nodeChildRichText.nextSibling 
								
							Wend
						End If
						
						
					End If
					Set nodeChildOfRTOne = nodeChildOfRTOne.nextSibling
				Wend
				
				
			End If
		End If
	Next
	Stop
	

Subroutine:
Code
Public Sub PlayWithDxlRoutine(domParser As NotesDomParser) 
	
	
	domParser.serialize
	
	
End Sub

2 files in c:\temp
RichText.xml und RichTextNew.xml
RichTextNew.xml kann einfach eine leere Datei sein.

RichText.xml
Code
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE document SYSTEM 'xmlschemas/domino_7_0.dtd'>
<document xmlns='http://www.lotus.com/dxl' version='7.0' replicaid='C125715F002D73D1'
 form='Sample'>
<noteinfo noteid='916' unid='7EE586C3D6B725CCC1257160004210E3' sequence='26'>
<created><datetime dst='true'>20060430T140136,99+02</datetime></created>
<modified><datetime dst='true'>20060501T143234,46+02</datetime></modified>
<revised><datetime dst='true'>20060501T143234,45+02</datetime></revised>
<lastaccessed><datetime dst='true'>20060501T143234,45+02</datetime></lastaccessed>
<addedtofile><datetime dst='true'>20060430T140144,62+02</datetime></addedtofile></noteinfo>
<updatedby><name>CN=Heinz Ulrich Krause/O=Witte/C=de</name></updatedby>
<revisions><datetime dst='true'>20060430T140144,62+02</datetime><datetime
 dst='true'>20060430T140243,32+02</datetime><datetime dst='true'>20060430T140318,98+02</datetime><datetime
 dst='true'>20060430T140350,65+02</datetime><datetime dst='true'>20060430T140423,73+02</datetime><datetime
 dst='true'>20060430T144720,51+02</datetime><datetime dst='true'>20060430T153953,81+02</datetime><datetime
 dst='true'>20060430T154101,45+02</datetime><datetime dst='true'>20060430T154103,21+02</datetime><datetime
 dst='true'>20060430T154143,04+02</datetime><datetime dst='true'>20060430T154235,77+02</datetime><datetime
 dst='true'>20060430T154437,24+02</datetime><datetime dst='true'>20060430T154904,73+02</datetime><datetime
 dst='true'>20060430T155631,37+02</datetime><datetime dst='true'>20060430T160359,38+02</datetime><datetime
 dst='true'>20060430T162002,11+02</datetime><datetime dst='true'>20060430T162040,60+02</datetime><datetime
 dst='true'>20060430T162107,21+02</datetime><datetime dst='true'>20060430T163828,93+02</datetime><datetime
 dst='true'>20060501T094942,46+02</datetime><datetime dst='true'>20060501T095028,39+02</datetime><datetime
 dst='true'>20060501T101412,59+02</datetime><datetime dst='true'>20060501T104914,32+02</datetime><datetime
 dst='true'>20060501T114738,49+02</datetime><datetime dst='true'>20060501T115259,27+02</datetime></revisions>
<item name='OriginalModTime'><datetime dst='true'>20060501T143234,44+02</datetime></item>

<item name='RTONE'>
<richtext>
<pardef id='1'/>
<par def='1'>TEST</par>
<par def='1'/>
<par def='1'>&lt;&lt;RT:RTTWO&gt;&gt;</par>
<par def='1'/>
<par def='1'>noch mehr Text</par>
</richtext>
</item>


<item name='RTTWO'><richtext>
<pardef id='2'/>
<par def='2'/></richtext></item>

<item name='TextField'><text/></item>

</document>
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 04.05.06 - 07:41:29
So, dank Stan Rogers habe ich es jetzt hinbekommen,

Zitat
'DOMParser:

Option Declare

Dim domParser As NotesDOMParser
Dim exporter As NotesDXLExporter
Dim importer As  NotesDXLImporter


Sub Click(Source As Button)
   Dim session As New NotesSession
   Dim db As NotesDatabase
   Set db = session.CurrentDatabase
   
   Dim dc As NotesDocumentCollection
   Set dc = db.UnprocessedDocuments
   If dc.Count = 0 Then
      Messagebox "No document selected",, "No document"
      Exit Sub
   End If
   Dim doc As NotesDocument
   Set doc = dc.GetFirstDocument
   
   Set exporter = session.CreateDXLExporter
   Set domParser=session.CreateDOMParser
   Set importer = session.CreateDXLImporter ( domParser, db )
   importer.DocumentImportOption = DXLIMPORTOPTION_REPLACE_ELSE_IGNORE
   
   Call exporter.SetInput ( doc )
   Call exporter.SetOutput ( domParser )
   Call domParser.SetOutput ( importer )
   On Event PostDOMParse From domParser Call PlayWithDXLRoutine   
   Call exporter.process
   
End Sub


Sub PlayWithDXLRoutine(Source As NotesDOMParser)
   Dim eNode As NotesDOMElementNode
   
   Dim cloneNode As NotesDOMNode   
   Dim i As Integer   
   Dim rootElement As NotesDOMElementNode
   Dim docList As NotesDOMNodeList   
   Dim node As NotesDOMNode   
   Dim nodeChildOfRTOne As NotesDOMNode
   Dim nodeChildRichText As NotesDOMNode
   Dim parNode As NotesDOMElementNode
   Set rootElement = domParser.Document.DocumentElement
   Set docList = rootElement.GetElementsByTagName ( "item" )
   
   If docList.NumberOfEntries = 0 Then :   Exit Sub
   
   For i = 1 To docList.NumberOfEntries
      Set node = docList.GetItem( i )
      Set enode = node
      If enode.GetAttribute("name") = "RTONE" Then
         If enode.hasChildNodes Then
            Set nodeChildOfRTOne = enode.FirstChild
            While Not (nodeChildOfRTOne.isNull)
               If nodeChildOfRTOne.NodeName = "richtext" Then
                  If nodeChildOfRtOne.hasChildNodes Then
                     Set  nodeChildRichText = nodeChildOfRTOne.FirstChild
                     While Not (nodeChildRichText.IsNull)
                        If nodeChildRichText.NodeName = "par" Then
                           Set parnode = nodeChildRichText
                           If ( Not parNode.FirstChild.IsNull ) Then ' skip NULL Values
                              If parnode.FirstChild.NodeValue = "RT:RTONE" Then
                                 parnode.FirstChild.NodeValue = "Hallo Welt"
                                 Msgbox "HEUREKA"
                              Else
                              End If
                           End If
                        End If
                        Set nodeChildRichText = nodeChildRichText.nextSibling
                     Wend
                  End If
               End If
               Set nodeChildOfRTOne = nodeChildOfRTOne.nextSibling
            Wend
         End If
      End If
   Next
   Call Source.Serialize
End Sub


Der Code ersetzt alle Vorkommen von RT:RTONE im gewählten Dokument durch die ausdrucksstarken Worte "Hallo Welt". Beeindruckend  ;D
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: Ralf_M_Petter am 04.05.06 - 08:10:51
Hallo Leute!

Habe diesen Thread leider erst jetzt entdeckt. Hatte genau diese Anforderung auch vor einiger Zeit. Bin über das fehlerhafte Einfügen von RichText gestossen und habe es dann mit DXL probiert. Hat auch prinzipiell geklappt nur jetzt kommts. DXL ist zumindest in unserer Notes Version 6.0.5 nicht vollständig implementiert. Das heisst, wenn du schönen RichText mit etwas aufwendigeren Formatierungen hast, dann schmeisst er alle Formatierungen die im DXL keine Entsprechung haben einfach weg. Ich habe es erst gemerkt als ich fertig war und mit Echtdaten getestet habe. Ich musste das ganze dann noch ein drittes mal machen und war echt Sauer auf die Programmierer von Lotus, die immer tolle Funktionen einbauen, die dann aber die eine oder andere Einschränkung haben, die die Verwendung behindern.

Grüße

Ralf

P.S. Trotzdem Gratulation und Danke für den tollen Code
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 04.05.06 - 08:20:52
Zitat
P.S. Trotzdem Gratulation und Danke für den tollen Code

Merci . Mühsam ernährt sich das Eichhörnchen  :D

Hast du evtl noch ein paar Tipps, wie man das ReplaceChild so füttert, daß man eine komplette XML Struktur einfügen kann ??

Prinzipiell funktioniert das:

Zitat
                              If parnode.FirstChild.NodeValue = "RT:RTONE" Then
                                 'parnode.FirstChild.NodeValue = "HELLO WORLD"
                                 Set cloneNode = parNode.FirstChild.clone (False)
                                 clonenode.NodeValue = REPLACE_WITH
'                                 Set notesDOMNode = notesDOMNode.ReplaceChild( newChild, oldChild )
                                 Set replaceNode = parnode.ReplaceChild ( clonenode, parNode.FirstChild )

Aber das Replace_With wird als Text eingefügt  ::)
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: Ralf_M_Petter am 04.05.06 - 08:35:47
Hallo Ulrich!

Habe es nicht in Lotus script gemacht sondern in Java, da ich das ganze sowieso in einem Java Programm gebraucht hätte. Wenn ich mich noch richtig erinnere fügte er wenn man einen ChildNode einfügt, der ein DocumentFragment ist automatisch den gesamten Unterbaum ein. Wie gesagt, ich habe es dann nach dem ein Prototyp gelaufen ist nicht mehr verfolgt auf  Grund der Einschränkung von DXL. Hattest du noch nicht diese Probleme, dass DXL nicht alle Formatierungen kann, bzw wie willst du in Zukunft damit umgehen?

Grüße

Ralf
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 04.05.06 - 08:37:50
Zitat
Hattest du noch nicht diese Probleme, dass DXL nicht alle Formatierungen kann, bzw wie willst du in Zukunft damit umgehen?

Ich glaube, bis dahin bin ich noch nicht vorgedrungen ...
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: animate am 04.05.06 - 08:53:54
Zitat
P.S. Trotzdem Gratulation und Danke für den tollen Code

Merci . Mühsam ernährt sich das Eichhörnchen  :D

Hast du evtl noch ein paar Tipps, wie man das ReplaceChild so füttert, daß man eine komplette XML Struktur einfügen kann ??

Prinzipiell funktioniert das:

Zitat
                              If parnode.FirstChild.NodeValue = "RT:RTONE" Then
                                 'parnode.FirstChild.NodeValue = "HELLO WORLD"
                                 Set cloneNode = parNode.FirstChild.clone (False)
                                 clonenode.NodeValue = REPLACE_WITH
'                                 Set notesDOMNode = notesDOMNode.ReplaceChild( newChild, oldChild )
                                 Set replaceNode = parnode.ReplaceChild ( clonenode, parNode.FirstChild )

Aber das Replace_With wird als Text eingefügt  ::)

Was bedeutet denn "wird als Text eingefügt".
Könntest du mal ein kleines Beispiel zeigen, wie es aussieht und eins wie es aussehen soll? Vielleicht kann ich mir dann besser was drunter vorstellen.

Das Attribut NodeValue, das du mit dem REPLACE_WITH befüllst, ist abhängig vom NodeType. Vielleicht liegts daran
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 04.05.06 - 13:01:25
Na, ich bin in meiner Naivität davon ausgegangen, daß der DomParser die <> Tags automatisch in neue Nodes umsetzt

So sollte aus dem <par>RT:RTONE</par> ein

<par><picture height='71px' width='108px'><notesbitmap>
lQAmAAAAAAAAAAAAAAABAAAAAAAAAGwARwAIAAEACAACAE0ABwCWAFUIAAAAAAAAAAAAADIAQwgD

...
</par>

werden.

die <> werden aber in als text betrachtet, so daß an der Stelle nicht das Bild sondern halt eben der String erscheint.

Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 04.05.06 - 13:35:45
Irgendwie habe ich das Gefühl, daß ich mit meinem Code in eben dieselbe Sackgasse laufe, wie Rocky Oliver

Zitat
Lesson Two: The NotesDOMParser lacks the InsertBefore method
Now that  the new node is moved into the desired document, it needs to be moved into the proper position. Normally the InsertBefore method could be used to move the node into the proper position; however the NotesDOMParser doesn't have an InsertBefore method either, so I basically decided to abandon using the NotesDOMParser altogether. Instead I went "low-tech". I now export the form to DXL, and then simply search the DXL for a particular text tag that I added to the form to find the location where the new code should go, then I use a LS version of @ReplaceSubstring to add the new code. Once the new code is added I reimport it into the database using the NotesDXLImporter. This method works GREAT, and is very very fast.

So, my basic conclusion is that the NotesDOMParser is nice for reading XML documents, but it is really not useful for manipulating XML documents in any advanced way.


( http://www.lotusgeek.com/SapphireOak/LotusGeekBlog.nsf/d6plinks/ROLR-6CTKKN )

Das FindAndReplace hatte ich ja anfangs auch schon probiert; allerdings habe ich das FindAndReplace der NotesRichTextRange class   verwendet, und das ist ja bei umfangreicheren Ersetzungen in die Grätsche gegangen.

Ich probiere das jetzt noch einmal mit einer eigenen Routine.
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 04.05.06 - 17:09:22
DOMParser ade; auch nach Re-Konfiguration des Tachyonenstrahls und NeuAusrichtung der DiLithium Matrix ist da nix zu löten an der Holzkiste ...

Ich versuche das jetzt mal mit DXLExport in ein RichTextFeld, zeilenweises AppendText in ein weiteres RTFeld; an den Stellen, wo das RT:Irgendwas steht, hole ich mir die Informationen zeilenweise aus einem weiteren RTFeld, in das ich per DXLExport die daten aus dem einzufügenden feld exportiert habe.
Sind die daten drin, hänge ich Zeile für Zeile den Rest unten an und importiere mittels DXLImport.
Dürfte nicht sonderlich performant sein, aber darauf kommt es mir jetzt nicht mehr an. Ich will das zum Laufen bekommen !!!

Rocky macht das auch mit FindAndReplace. Er hat vermutlich nicht mit groesseren Datenmangen getestet. Ich werde ihn mal fragen ...

Weitere Möglichkeit, wäre Java zu nehmen. Da kennt Axel bestimmt irgendwas, was man in Notes verwenden kann.

Oder MSXML ...

Oder ich schreibe das in c++ und stelle die benötigtnen Funktionen als dll zur Verfügung ...

Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: Thomas Schulte am 04.05.06 - 17:43:04
Midas 2?

oder übernächste Woche Montag doch mit einem langen Anlauf und spitzen Stiefeln mit Stahlkappen direkt in den Backstage Bereich reintreten.
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 04.05.06 - 17:49:08
Ich versuche das jetzt mal mit DXLEXPORT, NotesSTREAM und DXLIMPORT. Sind dann insgesamt 3 Files auf der Festplatte (!) Man kann ja nicht direkt in ein RT Feld streamen um es dann bequem DXL importen zu können. Da fehlen beim Stream die SetInput und SetOutput Methoden

Zitat
Midas 2?

Nein, aber unter c++ gibt es einen Haufen fertiger Libs, die das XML InsertBefore gut können ...
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: flaite am 04.05.06 - 17:54:20
Ich find das alles auch sehr umständlich selbst für die Behandlung meines "personal friends" Notes Richtext.
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 04.05.06 - 18:01:03
Das "umständlich" resultiert aber doch eigentlich daraus, daß man zwar ein wie ich finde mächtiges Tool ( DXL /XML ) zur Verfügung hat, es aber an ein paar elementaren Methoden fehlt, um außer einem Export / Import auch Manipulationen vornehmen zu können.

Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 04.05.06 - 18:16:55
Richtig umständlich wird es dann, wenn man das dynamisch macht und den Content aus mehreren RT Feldern zusmmenführen will. Ach, irgendwie ist das alles gequirlte Schei ...e.

Da hat man Ideen, wie man ein Programm funktional aufwerten kann, und dann kann man das nicht umsetzen ...

Ich frag jetzt Ben, ob er uns für HELP ein MIdas mit nur der einen Funktion zur Verfügung stellt.

Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: flaite am 04.05.06 - 19:40:12

Nein, aber unter c++ gibt es einen Haufen fertiger Libs, die das XML InsertBefore gut können ...
In Java auch. Das sind keine "xml-Probleme".
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 04.05.06 - 20:25:14
Das gestreame ( Ich teste gerade mit 2 einzufügenden xml Files ) in eine 10 MB grosse Datei ist so performant, wie 10000er Schmirgelpapier auf einer ungehobelten Dachlatte  :P

Nicht wirklich der Burner ...

Egal, ich lasse jetzt einfach mal den BimBam baumeln ...
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 05.05.06 - 19:23:18
ich habe noch ein wenig rumoptimiert.

Der einzige Weg, das Ziel zu erreichen ist ein MERGE zweier XML Dateien. Der Platzhalter ( RT:RTONE ) definiert dabei das RichTextFeld des Dokuments, welches in das Originaldokument eingefügt werden soll ( und eben auch die Position des Insert )

Wie schon erwähnt, kann man kein einzelnes Feld per DXLExport in ein XML File schreiben.
Daher muß man dafür sorgen, daß die MergeXML function genau die Stellen des XML merged, die dem RTONE entsprechen.

Der folgende Code extrahiert aus einem DXLExport die für das RichtextFeld RTONE relevanten Stellen.

aus:

Code
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE document SYSTEM 'xmlschemas/domino_7_0.dtd'>
<document xmlns='http://www.lotus.com/dxl' version='7.0' replicaid='C125716400442909'
 form='Sample'>
<noteinfo noteid='8fe' unid='5F51EAD9AF6B93A0C12571650030E607' sequence='17'>
<created><datetime dst='true'>20060505T105406,15+02</datetime></created>
<modified><datetime dst='true'>20060505T184225,59+02</datetime></modified>
<revised><datetime dst='true'>20060505T184225,58+02</datetime></revised>
<lastaccessed><datetime dst='true'>20060505T184225,58+02</datetime></lastaccessed>
<addedtofile><datetime dst='true'>20060505T105424,71+02</datetime></addedtofile></noteinfo>
<updatedby><name>CN=Heinz Ulrich Krause/O=Witte/C=de</name></updatedby>
<revisions><datetime dst='true'>20060505T105424,71+02</datetime><datetime
 dst='true'>20060505T182943,24+02</datetime><datetime dst='true'>20060505T183029,98+02</datetime><datetime
 dst='true'>20060505T183236,20+02</datetime></revisions>
<item name='OriginalModTime'><datetime dst='true'>20060505T184225,58+02</datetime></item>
<item name='RTONE'><richtext>
<pardef id='1'/>
<par def='1'><run><font style='bold italic underline' color='red'/>Dieser Text soll eingefügt werden</run></par></richtext></item>
<item name='RTTWO'><richtext>
<pardef id='2'/>
<par def='2'/></richtext></item>
<item name='TextField'><text/></item></document>

wird

Code
<par def='1'><run><font style='bold italic underline' color='red'/>Dieser Text soll eingefügt werden</run></par>

Da wo jetzt ein Print m_stream_buf steht, werden die Daten über ein rt.Appendtext ( m_stream_bufbuf ) in ein RT Feld in das SoureXML gemerged.

Anschließend aktualisiert ein DXLImporter das Ursprungsdokument.

Attachments brauchen wieder eine Sonderbehandlung, da ja auch die $File - Daten  in das Ursprungsdokument übernommen werden müssen. ( wie das geht; nach der nächsten MAUS )

Code
Sub Click(Source As Button)
	
	Const RT_FIELD = "RTONE"
	
	MergeFile = "c:\RichText.xml"
	Dim s As New NotesSession
	Dim db As NotesDatabase
	Set db = s.CurrentDatabase
	
	Dim m_stream As NotesStream
	Dim m_stream_buf As String
	
	Set m_stream = s.CreateStream
	If ( Not m_stream.open ( MergeFile )) Then
		Exit Sub
	End If
	
	Do
		m_stream_buf = m_stream.ReadText ( STMREAD_LINE, 4 )
		If Instr ( m_stream_buf, |<item name='| ) > 0 And Instr ( m_stream_buf, RT_FIELD ) > 0 Then
			Do
				m_stream_buf = m_stream.ReadText ( STMREAD_LINE, 4 )
				If Instr ( m_stream_buf, |<pardef| ) > 0 Then
					m_stream_buf = m_stream.ReadText ( STMREAD_LINE, 4 )
				End If
				If Instr ( m_stream_buf, |</richtext></item>| ) > 0 Then
					m_stream_buf = Left$ ( m_stream_buf, Len ( m_stream_buf ) - ( Len ( |</richtext></item>| ) +1 )  )
					Print m_stream_buf
					Exit Do
				End If
				Print m_stream_buf
			Loop Until Instr(m_stream_buf, |</item>| ) > 0
		End If
	Loop Until m_stream.IsEOS	
	
	m_stream.Close
	
End Sub

Auch wenn es bei grossen Datenmangen ( beide Files ~ 100 MB ) nicht sonderlich performant ist, kommt man schlussendlich zum Ziel: Richtext in RichText einfügen !!

Soweit mein Ansatz

(http://www.eknori.de//_data/MacGyver.jpg)

Grandios auch die Tatsache, daß der Fred schon fast 600 Mal angesehen wurde; es gibt offenbar ein Bedürfnis für eine solche Funktion.
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 05.05.06 - 23:21:15
ich baue gerade an dem Code, zu ermitteln, ob in dem zu mergenden Code ein Attachment enthalten ist.

Muss ich denn jedes Stückchen Code selber hier posten ?
Ich habe zu dem Thema schon einige Steilvorlagen gegeben.

Ich wünsche mr. daß mal jemand den bisher geposteten Code aufschnappt und weiterentwickelt ... und sein  Ergebnis hier auch postet.

Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 06.05.06 - 00:22:25
ich fange gerade an, meien IPod zu lieben; Stevie Nicks säuselt mir gerade DREAMS in die Ohren, während ich über meinem Code sitze. Eine nahezu ideale Symbiose zwischen Geek und Musik.  O0

Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: Thomas Schulte am 06.05.06 - 07:52:54
Würde ich ja gerne machen, aber was du da gerade tust ist im Moment jenseits meines Verständnishorizontes.
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 07.05.06 - 12:40:40
Grundsätzlich funktioniert das mergen jetzt

Hier der Code

Code
Function MergeXML ( SourceFile As String, MergeFile As String ) As Boolean
	MergeXML = False
	
	Const RT_FIELD = "RTONE"
	Dim s As New NotesSession
	Dim db As NotesDatabase
	Set db = s.CurrentDatabase
	
	Dim tmpDoc As NotesDocument
	Set tmpDoc = New NotesDocument(db)
	Dim rtXML As New NotesRichTextItem (tmpDoc, "Body")
	
	Dim s_stream As NotesStream
	Dim m_stream As NotesStream
	Dim s_stream_buf As String
	Dim m_stream_buf As String
	Dim HAS_ATTACHMENTS As Boolean 
	Dim i As Integer	
	
	Set s_stream = s.CreateStream
	If ( Not s_stream.open ( SourceFile )) Then
		Exit Function
	End If
	
	i = 1
	HAS_ATTACHMENTS = False
	' Read the Source File line by line
	Do 
		s_stream_buf = s_stream.ReadText ( STMREAD_LINE, 4 )
		Do While Instr ( Ucase ( s_stream_buf ) , Ucase ( "RT:" + RT_FIELD ) )> 0
			' insert data from merge file
			Set m_stream = s.CreateStream 
			If ( Not m_stream.open ( MergeFile )) Then
				Exit Function
			End If
		     ' Read the MergeFile line by line
			Do
				m_stream_buf = m_stream.ReadText ( STMREAD_LINE, 4 )
				
				If Instr ( Ucase ( m_stream_buf ) , Ucase ( |<item name='| + RT_FIELD +|'>|) ) > 0  Then
					Do
						m_stream_buf = m_stream.ReadText ( STMREAD_LINE, 4 )
						If Instr ( m_stream_buf, |<pardef| ) > 0 Then
							m_stream_buf = m_stream.ReadText ( STMREAD_LINE, 4 )
						End If
						If Instr ( m_stream_buf, |</richtext></item>| ) > 0 Then
							m_stream_buf = Left$ ( m_stream_buf, Len ( m_stream_buf ) - ( Len ( |</richtext></item>| ) +1 )  )
							Call rtXML.AppendText ( m_stream_buf )
							Exit Do
						End If
						
						Dim pos As Long
						pos = Instr ( Ucase ( m_stream_buf ) , Ucase ( |<attachmentref name='| ) ) 
						If pos > 0  Then
							' Determine the <attachmentref name= of all attachments in mergefile
							' and store names in array for further use
							HAS_ATTACHMENTS = True
							Redim Preserve AttNames ( i ) As String
							AttNames ( i -1 ) = Mid ( m_stream_buf , pos +21 , Instr (Mid ( m_stream_buf , pos + 21 , ( Len(m_stream_buf ) - 21 ))  , |'|) -1  )
							i = i +1
						End If
						
						Call rtXML.AppendText ( m_stream_buf )
					Loop Until Instr(m_stream_buf, |</item>| ) > 0
					Exit Do
				End If
			Loop Until m_stream.IsEOS	
			
			Dim m_stream_pos As Long
			m_stream_pos = m_stream.Position 'store current stream location 
			
			m_stream.Close ' close stream
			s_stream_buf = s_stream.ReadText ( STMREAD_LINE, 4 )' read next line 
		Loop
		
		If HAS_ATTACHMENTS And Instr ( s_stream_buf,  |</document>| ) > 0 Then
			' strip the </document> tag from s_stream_buf  
			Call rtXML.AppendText ( Replace ( s_stream_buf , |</document>| , "" ) )
			' append filedata
			Set m_stream = s.CreateStream 
			
			If ( Not m_stream.open ( MergeFile )) Then
				Exit Function
			End If
			m_stream.Position = m_stream_pos
			Do
				m_stream_buf = m_stream.ReadText ( STMREAD_LINE, 4 )
				
				'If Instr ( Ucase ( m_stream_buf ) , Ucase ( |<item name='| + RT_FIELD +|'>|) ) > 0  Then
				Call rtXML.AppendText ( m_stream_buf )	
				'End If
				
			Loop Until m_stream.IsEOS
			m_stream.Close ' close stream
			' finally add </document> tag 
			'Call rtXML.AppendText ( |</document>| )
		Else
			Call rtXML.AppendText ( s_stream_buf )
		End If
		
	Loop Until s_stream.IsEOS	
	
	s_stream.Close
	
	tmpdoc.Form = "Memo"
	tmpdoc.SendTo = "Heinz Ulrich Krause/Witte/de"
	Call tmpdoc.send ( False )
	
	Dim importer As NotesDXLImporter
	Set importer = s.CreateDXLImporter ( rtXML , db )
	importer.DocumentImportOption = DXLIMPORTOPTION_REPLACE_ELSE_IGNORE
	Call importer.Process
	
	Kill ( sourceFile )
	Kill ( mergeFile )	
	MergeXML = True
	
End Function

Es gibt noch 2 kleinere Probleme, die zu lösen sind.

1. Wenn nach der Einfügemarke am Ende des RichTextFeldes kein CRLF erfolgt, steigt der DXLImporter mit einem Fehler aus.

2. zur Zeit werden ALLE Attachments des MergeDoc übernommen. Hier muss ich noch nach den nur im gewünschten Feld enthaltenen Attachments filtern.

Ausserdem ist die Marke RT:RTONE z.Zt. noch fest verdrahtet, aber das ist kein Problem, die Marken im RT des SourceDoc zu ermitteln.  :D
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 07.05.06 - 14:11:57
Hier noch der Codeteil, der die relevanten $FILE Informationen aus dem MergeDoc extrahiert

Code
			Forall m In AttNames
				
				Set m_stream = s.CreateStream 
				
				If ( Not m_stream.open ( MergeFile )) Then
					Exit Function
				End If
				m_stream.Position = m_stream_pos
				
				
				Dim FILENAME As String
				FILENAME = Cstr ( m )
				Dim tmp_buf As String
				
				Do
					m_stream_buf = m_stream.ReadText ( STMREAD_LINE, 4 )
					If Instr ( m_stream_buf , |<item name='$FILE'| ) > 0 Then
						tmp_buf = m_stream_buf
						m_stream_buf = m_stream.ReadText ( STMREAD_LINE, 4 )
						
						If Instr ( m_stream_buf , FILENAME ) > 0 Then
							
							Call rtXML.AppendText ( tmp_buf )
							Call rtXML.AppendText (  m_stream_buf )
							
							Do	
								
								m_stream_buf = m_stream.ReadText ( STMREAD_LINE, 4 )
								m_stream_buf = Replace ( m_stream_buf , |</document>| , "" )
								Call rtXML.AppendText (  m_stream_buf )
								
							Loop Until  Instr ( m_stream_buf , |</item>| ) > 0 
							
						End If	
					End If
					
				Loop Until m_stream.IsEOS
				Call m_stream.Close
				
			End Forall

Titel: Re: RichText in RichText EINFÜGEN ( Final Solution )
Beitrag von: eknori am 07.05.06 - 17:04:19
Hier nun der endgültige Code + eine Sample DB

Code
Const PATHNAME = "c:\"

Sub Click(Source As Button)
	
	Dim s As New NotesSession
	Dim db As NotesDatabase
	Dim dc As NotesDocumentCollection
	Dim doc As NotesDocument
	Dim ret As Boolean	
	Set db = s.CurrentDatabase
	Set dc = db.UnprocessedDocuments
	Set doc = dc.GetFirstDocument
	
	Dim SourceFileName As String
	Dim MergeFileName As String
	
	SourceFileName = ExportXML ( doc )
	Set doc = dc.GetNextDocument ( doc )
	MergeFileName = ExportXML ( doc )
	
	ret  = InsertRichText ( SourceFileName , MergeFileName ,"RTONE")
	
End Sub


Function  ExportXML ( doc As NotesDocument ) As String
	
	Dim s As New NotesSession
	Dim stream As NotesStream
	Set stream = s.CreateStream
	Dim exporter As NotesDXLExporter
	Dim FILENAME As String
	Dim universalID As String*32
	
	universalID = doc.UniversalID
	
	FILENAME = PATHNAME + universalID +".xml"
	If Not stream.Open ( FILENAME ) Then
		Messagebox "Cannot open " & FILENAME,, "Error"
		Exit Function
	End If
	Call stream.Truncate
	
	Set exporter = s.CreateDXLExporter
	Call exporter.SetInput ( doc )
	Call exporter.SetOutput ( stream )
	Call exporter.Process
	ExportXML = FILENAME
	
End Function

Function InsertRichText ( SourceFile As String, MergeFile As String, FieldName As String)  As Boolean
%REM
	INSERTS a NotesRichTextItem into another NotesRichTextItem. 
	You can define the insertion point by writing a RT:<SomeFieldName> - Tag into the field where the Richtext 
	should be inserted.

	Known issues:
	
	If RT:RTONE is located at the end of the RTItem it has to be terminated by a CRLF. Otherwise the DXLImpoter
	fails.
%END REM
	InsertRichText = False
	
	Dim s As New NotesSession
	Dim db As NotesDatabase
	Set db = s.CurrentDatabase
	
	Dim tmpDoc As NotesDocument
	Set tmpDoc = New NotesDocument(db)
	Dim rtXML As New NotesRichTextItem (tmpDoc, "Body")
	
	Dim s_stream As NotesStream
	Dim m_stream As NotesStream
	Dim s_stream_buf As String
	Dim m_stream_buf As String
	Dim HAS_ATTACHMENTS As Boolean 
	HAS_ATTACHMENTS = False	
	Dim i As Integer	
	i = 1
	
	' Open source stream
	Set s_stream = s.CreateStream
	If ( Not s_stream.open ( SourceFile )) Then
		Exit Function
	End If
	' Read the Source File line by line
	Do 
		s_stream_buf = s_stream.ReadText ( STMREAD_LINE, 4 )
		Do While Instr ( Ucase ( s_stream_buf ) , Ucase ( "RT:" + FieldName ) )> 0
			' insert data from merge file
			Set m_stream = s.CreateStream 
			If ( Not m_stream.open ( MergeFile )) Then
				Exit Function
			End If
		     ' Read the MergeFile line by line
			Do
				m_stream_buf = m_stream.ReadText ( STMREAD_LINE, 4 )
				
				If Instr ( Ucase ( m_stream_buf ) , Ucase ( "<item name='" + FieldName +"'>" )) > 0  Then
					Do
						m_stream_buf = m_stream.ReadText ( STMREAD_LINE, 4 )
						If Instr ( m_stream_buf, "<pardef" ) > 0 Then
							m_stream_buf = m_stream.ReadText ( STMREAD_LINE, 4 )
						End If
						If Instr ( m_stream_buf, "</richtext></item>" ) > 0 Then
							m_stream_buf = Left$ ( m_stream_buf,_
							Len ( m_stream_buf ) - ( Len ( "</richtext></item>" ) +1 ) )
							
							Call rtXML.AppendText ( m_stream_buf )
							Exit Do
						End If
						
						Dim pos As Long
						pos = Instr ( Ucase ( m_stream_buf ) , Ucase ( "<attachmentref name='" ) ) 
						If pos > 0  Then
							' Determine the <attachmentref name= of all attachments in mergefile
							' and store names in array for further use
							HAS_ATTACHMENTS = True
							Redim Preserve AttNames ( i ) As String
							AttNames ( i -1 ) =_
							Mid ( m_stream_buf , pos +21 ,_
							Instr (Mid ( m_stream_buf , pos + 21 ,_
							( Len(m_stream_buf ) - 21 ))  , "'") -1  )
							i = i +1
							
						End If
						
						Call rtXML.AppendText ( m_stream_buf )
					Loop Until Instr(m_stream_buf, "</item>" ) > 0
					Exit Do
				End If
			Loop Until m_stream.IsEOS	
			
			Dim m_stream_pos As Long
			m_stream_pos = m_stream.Position 'store current stream position 
			
			m_stream.Close ' close stream
			s_stream_buf = s_stream.ReadText ( STMREAD_LINE, 4 )' read next line 
		Loop
		
		If HAS_ATTACHMENTS And Instr ( s_stream_buf,  "</document>" ) > 0 Then
			' strip the </document> tag from s_stream_buf  
			Call rtXML.AppendText ( Replace ( s_stream_buf , "</document>" , "" ) )
			' append filedata
			Forall m In AttNames
				If Trim ( Cstr ( m )) = "" Then Exit Forall
				Set m_stream = s.CreateStream 
				
				If ( Not m_stream.open ( MergeFile )) Then
					Exit Function
				End If
				' do not read from beginning of stream but restore last position
				m_stream.Position = m_stream_pos
				
				Dim FILENAME As String
				FILENAME = Cstr ( m )
				Dim tmp_buf As String
				
				Do
					m_stream_buf = m_stream.ReadText ( STMREAD_LINE, 4 )
					If Instr ( m_stream_buf , "<item name='$FILE'" ) > 0 Then
						tmp_buf = m_stream_buf ' 
						m_stream_buf = m_stream.ReadText ( STMREAD_LINE, 4 )
						
						If Instr ( m_stream_buf , FILENAME ) > 0 Then
							Call rtXML.AppendText ( tmp_buf )
							Call rtXML.AppendText (  m_stream_buf )
							' loop through all lines until </item> is found
							Do	
								m_stream_buf = m_stream.ReadText ( STMREAD_LINE, 4 )
								m_stream_buf = Replace ( m_stream_buf , "</document>" , "" )
								Call rtXML.AppendText (  m_stream_buf )
							Loop Until  Instr ( m_stream_buf , "</item>" ) > 0 
						End If	
					End If
				Loop Until m_stream.IsEOS
				Call m_stream.Close
				
			End Forall
			' finally append the closing tag </document>
			Call rtXML.AppendText ( "</document>" )
		Else
			Call rtXML.AppendText ( s_stream_buf )
		End If
		
	Loop Until s_stream.IsEOS	
	s_stream.Close ' close dtream
	
	' import the XML data and update the source document	
	Dim importer As NotesDXLImporter
	Set importer = s.CreateDXLImporter ( rtXML , db )
	importer.DocumentImportOption = DXLIMPORTOPTION_REPLACE_ELSE_IGNORE
	Call importer.Process
	' delete the exported files from the filesystem
	Kill ( sourceFile )
	Kill ( mergeFile )	
	InsertRichText = True
	
End Function

Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 07.05.06 - 19:28:26
ein kleines Problem gibt es noch, wenn man die Einfügemarke mehrfach einfügt ( das wirkt sich aber nur bei Anhängen aus )

Da werden dann auch die $FILE Daten mehrfach erzeugt; Solange man die Anhänge nicht bearbeitet und wieder in das Dokument einfügt, macht das aber nichts. Außer daß das Dokument in der Groesse anwächst. Ich habe aber schon eine Idee, wie man das lösen kann...

Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 08.05.06 - 19:43:35
Um das Attachment Problem in den Griff zu bekommen, ist mächtig viel zusätzlicher Code nötig.

Hängt man das gleiche Attachment zweimal in ein RichtextFeld, dann sieht das im DXL so aus

1. Attachment
Zitat
<attachmentref name='2nd.jpg' displayname='2nd.jpg'><picture
 height='47px' width='43px'><notesbitmap>

2. Attachment, gleicher Dateiname
Zitat
<attachmentref name='ATT5OTO6' displayname='2nd.jpg'><picture
 height='47px' width='43px'><notesbitmap>

Verwendet man nun n-Mal den Tag <<RT:RTONE>>, dann werden auch diese Informationen dupliziert.
Das wäre soweit nicht weiter schlimm, wenn der DXLIMporter das merken würde und die
<attachmentref name='ATTxxxxxx> entsprechend selber anpassen würde. Tut er aber nicht. Das Ding ist dumm wie Brot und importiert daß, was man ihm vorsetzt; Hauptsache Well-Formed.

Probleme bekommt man dann, wenn man im Nachhinein eins der doppelten Attachments mit gleicher <attachmentref name='ATT bearbeitet. PENG !!!

Man kann jetzt sagen, OK, dann darf es halt keine doppelten Platzhalter geben. Aber daß Problem tritt auch dann auf, wenn man ( wie es in !!HELP!! beabsichtigt ist )

<<RT:RTONE>>
<<RT:RTTWO>>

verwendet, wobei RTONE und RTTWO aus unterschiedlichen Dokumenten kommen, aber durchaus das gleiche Attachment haben können ( nicht müssen )

Also muss man, nachdem das komplette XML im RT zusammengebastelt ist, <attachmentref name='ATTxxxxx und die dazugehörenden DisplayName - Tags unique machen.

Das ist noch eine Menge Arbeit, ist aber nicht unlösbar ( NotesRichTextNavigator und NotesRichTextRange )

Ich denke, daß es mit DXL im Backend eine Menge Möglichkeiten gibt. Solange es nicht zeitkritisch ist.
Schön ist auch, daß man im DXl mal sieht, wie so ein RT-Field intern "tickt".

Allerdings suche ich noch nach Informationen, wie man den DXLImporter ein wenig mehr detailliertere Informationen entlockt als ewig die gleiche monotone Fehlermeldung, wenn das XML nicht well-formed ist.
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: flaite am 08.05.06 - 23:02:45
Hi,

kannst du vielleicht einfach mal eine Beispieldatenbank posten?
Oder kann ich einfach meine HELP Version nehmen, deinen Agenten da rein pasten und dann bestimmte Felder mit bestimmten Werten füllen?

Zitat
Allerdings suche ich noch nach Informationen, wie man den DXLImporter ein wenig mehr detailliertere Informationen entlockt als ewig die gleiche monotone Fehlermeldung, wenn das XML nicht well-formed ist.
Nicht normal. Aus allen mir bekannten xml Parsern bekommt man die Zeilen/Spaltennummer bzgl. wo es nicht well formed ist.
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 09.05.06 - 05:10:51
du könntest die Beispieldatenbank nehmen, die ich dem vorletzten Post angehängt habe.
erstes Doc enthält den Platzhalter und zweites doc die Daten, die eingefügt werden sollen.

Um einen Fehler zu produzieren, schreibe das bekannte RT:RTONE als einzigen Eintrag in das erste doc ( ohne abschließendes CRLF und ohne Zeichen vor dem Platzhalter )
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 16.05.06 - 18:22:15
mit ein wenig mehr code ist es sogar möglich, ohne Platzhalter zu arbeiten und einfach als Parameter ein INSERT_AFTER_TABLE oder INSERT_BEFORE_EMBEDDED zu übergeben.

Zumindest werde ich das mal in diese Richtung weiterentwickeln.

Möglicherweise liest das ja aber auch einer von IBM und sagt: "Mensch, das ist ja mal ne klasse Funktion, die bauen wir ein !". Zumindest wurde ja gestern auf der DNUG genau dies propagiert. IBM schaut sich die Blogs an und wenn die Leute meinen, daß eine bestimmte Funktion ins Produkt reinmuss, dann wird das auch gemacht.

Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 16.05.06 - 19:28:40
Wenn ich mir so die Möglichkeiten im Workplace Designer anschaue, muss ich feststellen, daß es auch dort wohl nicht möglich sein wird, RT in RT einzufügen. ...



Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 17.05.06 - 07:25:19
Ich habe mal bei IBM einen enhancement request gestellt

Zitat
PMR Nummer 28964 032 724 wurde vom IBM Support erfolgreich erstellt. Sie enthält die folgende Kurzbeschreibung:
enhancement request: It is not possible to programmatically INSERT Richtext into Richtext. Pls. enhance the NotesRichTextItem class by a method

Call NotesRichTextItem.insertRTItem ( source as NotesRichtextItem, position as NotSureAboutType )
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 24.05.06 - 09:20:05
update:
Zitat
...
I have created this enhancement request on your behalf. If it is decided
to address this request, it will be listed in our fixlist database:
http://www-10.lotus.com/ldd/r5fixlist.nsf

Its unlikely that this problem will be addressed in the current
codestream, however when new releases and maintenance releases are
released you can check if this request has been addressed by searching
for SPR # BHUY6PVGW3.
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 18.09.06 - 19:03:40
Update:

In der c++ API 3.0 gibt es ü brigens eine Methode LNRichText::Insert. Damit läßt sich plain text, richtext und Objekte an eine beliebige Stelle in einem RTFeld einfügen. Und wenn ich das richtig verstehe, ist das auch im Backend möglich.

Bevor jetzt hier aber alle "Hurra" schreien; da ist noch eine Menge drumherum zu programmieren.
Sollte mein Laptop jemals mal geliefert werden, werde ich mich mal an die Umsetzung machen.

Ach ja, die API stellt auch eine methode zur verfügung um zu testen, ob ein RTFeld leer ist. Da wurde, glaube ich, hier und anderswo auch schon häufiger nach gefragt.
Titel: Re: RichText in RichText EINFÜGEN - die c++ Variante
Beitrag von: eknori am 24.09.06 - 15:59:29
Habe heute ein bisschen mit der API herungespielt. Herausgekommen ist folgender Code, der den Inhalt aus einem Richtextfeld in ein anderes Richtextfeld an einer bestimmten Stelle einfügt. Die Einfügemarke ist "<RTINSERT>".

Der Code ersetzt alles Vorkommen von <RTINSERT> mit dem Inhalt des RTFeldes aus einem anderen Dokument.

Das Ganze ist selbstverständlich keine komplette Lösung, die man jetzt sofort in seine eigenen Anwendungen kopieren kann.

Code
/*
Insert richtext into richtext
Ulrich Krause, 2006
*/

#include <LNCPPAPI.H>
#include <iostream>
using namespace std; // VS2003 uses namespaces so add this line. You could prefix cout with std::cout instead.

int main(int argc, char *argv[])  {

char errorBuf [LNERROR_MESSAGE_LENGTH];

LNNotesSession	s;
LNDatabase	db;
LNDocument	docA;
LNDocument	docB;
LNDocumentArray	col;
LNRichText	rtA;
LNRichText	rtB;
LNRTCursor	cursor;
LNSTATUS   lnstatus = LNNOERROR;

LNSetThrowAllErrors( TRUE ); // get the API to trow catchable errors rather than return a status code from each operation.

try 	{

	s.Init();
	s.GetDatabase("richtext.nsf", &db, "");
	db.Open();

	db.GetDocuments(&col); // Get All documents in the database
	docA = col[0]; // Get First Document
	docB = col[1]; // Get Second Document
	docA.Open(); // Open Document
	docB.Open(); // Open Document
	docA.GetItem("Body", &rtA); // Get Body Field
	docB.GetItem("Body", &rtB); // Get Body Field
	//Get a cursor pointing at the first element in the rich text.
	rtA.GetCursor(&cursor);

		lnstatus = cursor.GotoFirst ( "<RTINSERT>" );

			//Loop through the end of the document.
			while ( lnstatus != LNWARN_NOT_FOUND) 
			{
				//Delete the original text string.
				rtA.Delete( &cursor, 10);
				//Replace the text string with the new one.
				rtA.Insert( rtB ,&cursor);
				//We have to save the doc before doing the next step
				docA.Save();
				//Go find the next string occurrence.
				lnstatus = cursor.GotoNext( "<RTINSERT>" );
			}

	docA.Close();
	docB.Close();
	}

catch (LNSTATUS error ) 	{

	LNGetErrorMessage( error, errorBuf);
	cout << "Error: " << errorBuf << endl;

	}

db.Close();
s.Term();
return 0;
}

Die Bilder zeigen das Dokument mit der Einfügemarke, den RT, der eingefügt werden soll und das Ergebnis.
Es werden alle Objekte eingefügt, alle Formatierungen bleiben erhalten.
Titel: Re: RichText in RichText EINFÜGEN
Beitrag von: eknori am 15.10.06 - 15:37:53
Der guten Ordnung halber hier noch die komplette Lösung zum Download http://www.eknori.de/archives/348