Das Notes Forum
Domino 9 und frühere Versionen => ND6: Entwicklung => Thema gestartet von: eknori am 15.08.05 - 17:15:51
-
Hat jemand erfahrung mit diesen beiden Klassen ??
Ich knobele gerade an folgenden Problem:
Ein RichtextItem enthält z.B. folgenden Text:
Sehr geehrter Herr <<RCPT>>,
Ihre Anfrage <<REQNUMBER>> wird von unserem Mitarbeiter <<SUPPORTER>> bearbeitet.
Ich möchte jetzt die <<>> Tags durch Werte aus dem Ticket ersetzen, wobei die Strings innerhalb der <<>> Feldnamen darstellen.
Mittels
If rtnav.FindFirstString("<<", _
RT_FIND_CASEINSENSITIVE) Then
Do
Call rtrange.SetBegin(rtnav)
'Messagebox rtrange.textParagraph,, "<<"
' und wie geht es dann hier weiter ??
Loop While rtnav.FindNextString("<<", _
RT_FIND_CASEINSENSITIVE)
Else
Messagebox "<<",, "String not found"
End If
komme ich auch immer an das nächste <<
Aber wie mache ich jetzt das Replace ?
If rtnav.FindFirstString("<<", _
RT_FIND_CASEINSENSITIVE) Then
Do
Call rtrange.SetBegin(rtnav)
'Messagebox rtrange.textParagraph,, "<<"
While rtrange.FindAndReplace _
("<<RCPT>>",_ ' find
CommonNameString (Trim(atWord(Cstr(m),"|",1))),_ ' replace
RT_FIND_CASEINSENSITIVE) > 0
Call rtItem.Update ' Must update before looping
Wend
Loop While rtnav.FindNextString("<<", _
RT_FIND_CASEINSENSITIVE)
Else
Messagebox "<<",, "String not found"
End If
Dieses Konstrukt funktioniert nicht ( ich weiß, daß hier einiges Hardcodiert ist, aber <<RCPT>> ist der erste Tag im Text.
Im Debugger meckert er immer die Zeile mit dem Wend an.
Jemand schon mal die Kombination der Klassen programmiert ( In der Notes Hilfe ist alles separat beschrieben, aber nicht in der Kombination ) Irgendwie scheinen sich die ursprünglich erzeugten Objecte rtNav und rtRange selber zu "zerstören"
-
Ich habe ein ähnliches "RichText Templating" mit den neuen Klassen vor.
Deshalb hab ich ein deutliches Interesse an deinem Erfolg.
Ich hoffe, ich habe das beim raschen Überfliegen verstanden, aber für mich wirkt es eventuell erfolgversprechender, wenn wir statt eines Replace ein ganz neues RichTextItem mit eigenem RichTextNavigator erzeugen und das dann Stück für Stück aus dem geparsten Zeug erzeugen?
Möglicherweise ist das ein bischen verwirrend und vielleicht auch falsch aber ich bin selbst noob in diesem Thema.
Axel
-
wenn wir statt eines Replace ein ganz neues RichTextItem mit eigenem RichTextNavigator erzeugen und das dann Stück für Stück aus dem geparsten Zeug erzeugen
ist zumindest einen Versuch wert.
Habe mir auch schon überlegt, mir erst die <<TAG>> Tags in ein Array zu schreiben und dann in einem zweiten Step mit FindReplace das ursprüngliche RTItem zu bearbeiten. Ich glaube, daß ist einfacher, als sich jedesmal den RTNavigator neu zu erzeugen ...
-
strTemp = ""
If rtnav.FindFirstString("<<", _
RT_FIND_CASEINSENSITIVE) Then
Do
Call rtrange.SetBegin(rtnav)
strTemp = strTemp + "~" + Mid(rtrange.textRun, 3, Instr( rtrange.textRun,">") -3 )
Loop While rtnav.FindNextString("<<", _
RT_FIND_CASEINSENSITIVE)
End If
Dim ret As Variant
ret = Split ( strTemp, "~" )
Msgbox ret(1)
liefert mir in ret alle TAGS des RtItems zurück; der Rest ist dann recht einfach ...
OK, man muß ret jetzt noch unique zu machen.
dann kann man mir
forall x in ret.values
sich jeweils einen Wert nach dem anderen vornehmen, sich den Wert des korrespondierenden Items aus dem Doc in der Collection holen und dann beschwingt mit:
While rtrange.FindAndReplace _
"<<" & CStr(x) & ">>",_ ' find
<ReplaceWithWertAusDoc>,_ ' replace
RT_FIND_CASEINSENSITIVE) > 0
Call rtItem.Update ' Must update before looping
Wend
alle Vorkommen von "<<" & CStr(x) & ">>" zu ersetzen.
ein rtItem.Update hinterhergeschossen und schon ist man fertig, oder ?
Das Drumherum ist dann Fleißarbeit, so mit ERRHANDLE und so ...
-
OK, kurz vor der Tagesschau noch schnell der funktionierende Code ( Ohne grossartiges ERRHANDLE ) für ein dynamisches FindandReplace in einem RT Item
Set rtnav = rtItem.CreateNavigator
Set rtrange = rtItem.CreateRange
strTemp = ""
If rtnav.FindFirstString ( TAG_PREFIX, _
RT_FIND_CASEINSENSITIVE) Then
Do
Call rtrange.SetBegin ( rtnav )
strTemp = strTemp + TAG_DELIMITER + Mid ( rtrange.textRun, 3, Instr( rtrange.textRun,TAG_SUFFIX ) -3 )
Loop While rtnav.FindNextString ( TAG_PREFIX, RT_FIND_CASEINSENSITIVE )
End If
Dim arrRetFieldNames As Variant
Dim ret As Integer
arrRetFieldNames = Arrayunique ( Split ( strTemp, TAG_DELIMITER ), 5 )
Set rtrange = rtItem.CreateRange
Dim strT As String
Forall t In arrRetFieldNames
strT = Cstr ( t )
If ( Not strT = "" ) Then
If ( Not ItemTextExists ( TicketDoc, strT ) = False) Then
ret = rtrange.FindAndReplace _
( TAG_PREFIX & strT & TAG_SUFFIX,_ ' find
TicketDoc.GetFirstItem( strT ).Text, _ ' replaceWith
RT_REPL_ALL) > 0
Call rtItem.Update ' Must update before looping
End If
End If
End Forall
@Axel: Ist das so i.O. ? Oder hast du noch eine bessere Idee ?
Oder hat sonstwer noch eine zündende IDEE ?? ( viele Kosumenten, wenig Produzenten )
-
Hallo Ulrich,
muss ich nachfragen:
Du "sammelst" zu Beginn Deiner Routine aus dem Richtext-Item die Platzhalter zusammen. Ist es dass, was Du mit "dynamischen FindAndReplace" meinst?
Sind die möglichen Platzhalter nicht schon vorher bekannt?
Gruß
Manfred
-
Sind die möglichen Platzhalter nicht schon vorher bekannt?
Wenn du die HelpdeskDB meinst, ja. Aber ich verwende den Code ( und die Designelemente ) auch in anderen DBs. Und da weiß ich nicht, welche Felder angesprochen werden .. Das ganze DIng, soll irgendwann mal so flexibel wie möglich sein ... nach dem Motto : Kopiere dies und das Designelemet in deine bestehende DB rein; konfiguriere dies und das und schon kannst du Benachrichtigungen nach deinen Vorstellungen rausschicken.
Das ist das Ziel, nicht mehr, nicht weniger ...
-
>>Aber ich verwende den Code ( und die Designelemente ) auch in anderen DBs. Und da weiß ich nicht, welche Felder angesprochen werden .. Das ganze DIng, soll irgendwann mal so flexibel wie möglich sein ...<<
OK. Dann ist die Lösung doch schon mal prima so.
Schönen Abend noch... :)
Manfred
-
OK. Dann ist die Lösung doch schon mal prima so.
Also nicht überzeugend ... Irgendwie Bockwurst ohne Senf ( scharf ) ??
Habe zumindest im Web noch keine Lösung gefunden, die meiner auch nur annähernd ähnlich kommt.
Oder es war keiner so d ... seine Lösung zu posten ...
Für meine Belange funktioniert der Code
-
Also nicht überzeugend ... Irgendwie Bockwurst ohne Senf ( scharf ) ??
Ach quatsch, das ist klasse.
Du könntest etwas ausprobieren, musste ich im Moment selbst testen, verwende ich so in der madicon easyMail ;) Anwendung.
Wenn Du ein rtrange festlegst:
Set doc = dc.GetFirstDocument
Set body = doc.GetFirstItem("Body")
Set rtrange = body.CreateRange
umfasst dieser rtrange das gesamte RichtextItem. Daher ist ein einziger Aufruf von:
count& = notesRichTextRange.FindAndReplace( target$ , replacement$ , [ options& ] )
ausreichend, wenn Du den optionalen Parameter "RT_REPL_ALL (16) to replace all occurrences of the search string" verwendest.
Das könnte etwas Performance bringen, da Du dann
- nicht mehr selbst nach dem Vorkommen suchen musst und
- Du nicht selbst von "Treffer" zu "Treffer" iterieren musst.
Gruß
Manfred
-
Ach, da fällt mir noch was ein, kannst Du bitte mal ausprobieren?
Man kann der Methode:
count& = notesRichTextRange.FindAndReplace( target$ , replacement$ , [ options& ] )
leider kein "" (also nix) als replacement$ übergeben. Wenn ich das mache, wird der "Platzhalter" einfach so wie er ist belassen. Minimum ist ein Leerzeichen (" ") erforderlich. Ist das bei Dir auch so?
Es gelingt einem so nicht, den "Platzhalter" komplett aus dem Inhalt des rtitems "rauszuwerfen".
Hast Du da noch eine Idee?
Gruß
Manfred
-
@Axel: Ist das so i.O. ? Oder hast du noch eine bessere Idee ?
Hm. Sieht gut aus. Danke.
Heute ist großer aber fixe-eine-verdammte-Schwäche-im-RDBMS-Design-und-ziehe-das-durch-2-Layer-Abend in einer anderen Anwendung >:(
Ich schau mir das auf jeden Fall mal an. Für mich schreibst du C-code. Ich kann das so nicht lesen. Müsste ich mir im Debugger mal anschauen. ;D
Was ich möchte ist eine Art Serienbrieffunktionalität, die auf den neuen RichText Funktionalitäten beruht. Meine Kunden haben nicht unbedingt alle MS-Word.
Da drin noch eine Art mini-Datenzugriffssprache, um auf Felder aus Dokumente auf vorher definierten Datenbanken/Ansichten zuzugreifen. Letzteres ist aber nicht so neu, wie die Möglichkeiten, die diese neuen RichText Klassen bieten.
Wichtig ist das die User Fehlermeldungen bekommen, mit denen sie etwas anfangen könnnen.
Die allgemein gebräuchlichen Teile werde ich jedenfalls auch posten.
Gruß Axel
-
count& = notesRichTextRange.FindAndReplace( target$ , replacement$ , [ options& ] )
ds ist mir klar; ich hatte das ja schon hier http://www.atnotes.de/index.php?topic=24716.msg158562#msg158562
gepostet.
aber ich kenne ja normalerweise zunächst target$ , replacement$ nicht ...
target$ hole ich mir einmalig, indem ich das Template auslese; Replacement$ hole ich mir aus dem doc in der collection of docs, die irgendwie an den Mann gebracht werden müssen.
-
Für mich schreibst du C-code
C-Code = nicht zu gebrauchender Code oder
c-Code = der Sprache C ähnlicher Code ??
-
aber ich kenne ja normalerweise zunächst target$ , replacement$ nicht ...
Zu Beginn Deiner Routine holst Du dir die Platzhalter, richtig? Das ist OK, die kennst Du ja nicht.
Weiter unten iterierst Du aber dann von "Fundstelle" zu "Fundstelle". Da könnte ein einziger Aufruf nach der von mir beschriebenen Weise ausreichen - natürlich ein Aufruf pro Platzhalter.
Manfred
-
ok, hab*s kapiert ... DANKE
habe das Posting ( http://www.atnotes.de/index.php?topic=25016.msg159881#msg159881 ) entsprechend ge-updated.
-
>> ok, hab*s kapiert ... DANKE<<
Na, klappt doch... ;D
BTW:
Liest Du noch mal meinen Post von oben? Von wegen "Platzhalter komplett rauswerfen"...
Manfred
-
das habe ich so noch nicht getestet´... muss ich mal machen
-
>> das habe ich so noch nicht getestet´... muss ich mal machen<<
Ja, wäre prima. Danke. Ergebnis auch gerne per eMail...
Noch ein Hinweis:
Deine oben geänderte Routine (der Austausch) ist nun nicht mehr "caseINsensitive". Musst Du noch was "dazutun". :)
Servus
Manfred
-
Für mich schreibst du C-code
C-Code = nicht zu gebrauchender Code oder
c-Code = der Sprache C ähnlicher Code ??
Das Zweite.
Wenn ich sage, dass ich das jetzt nicht lesen kann, heisst das überhaupt nicht, dass ich das für schlecht halte.
Ich habe großen Respekt vor dem Code von anderen Leuten. Ok. Sicher nicht alles. Aber das sieht extrem nach der Kategorie "gut, aber ich kapier das nicht direkt" aus. Bin ja mit diesen Klassen auch nicht so vertraut. ;)
-
Bin ja mit diesen Klassen auch nicht so vertraut
Kann ich nachvollziehen; bis vor ein paar Stunden kannte ich auch nur die halbe Whrheit; Dank an Manfred Dillmann für die Nachhilfe :D
Bemerkenswert finde ich, daß sich offensichtlich nur knapp eine Handvoll für die Anwendung der Klassen interessiert; immerhin aber gute Leute :D
-
Bemerkenswert finde ich, daß sich offensichtlich nur knapp eine Handvoll für die Anwendung der Klassen interessiert; immerhin aber gute Leute :D
Ich kann zu meiner Verteidigung nur vorbringen das in Bayern heute Feiertag ist. Aber der COdeschnipsel ist schon klasse. Danke dafür.
-
Noch ein Hinweis:
Deine oben geänderte Routine (der Austausch) ist nun nicht mehr "caseINsensitive". Musst Du noch was "dazutun".
Ja nee, iss klar ;D
-
Noch ein kleiner Hinweis zu der Ersetztengeschichte:
die funktion notesRichTextRange.FindAndReplace kann nicht nur keine "", sondern (und das finde ich schlimmer) auch keine mehrzeiligen Strings. Sprich: an eine gefundene Position einen String, der u.a. einem Zeilenumbruch CHR(13) enthält, zu setzen.
Und auch dein Codeschnispel kann das nicht...denn, sobald du an eine Stelle einen Text mit mehr als einer Zeile einfügst, verweigert FindNextString die Arbeit. Auch das rtitem.Update hilft da nicht.
Und das ist wohl der Grund warum FindAndReplace keine Umbrüche verarbeitet. Intern wird diese Funktion wohl auch mit einer Schleife FindFirst/FindNext arbeiten....und deshalb entfernt FindAndReplace kurzerhand alle CR/LF aus dem zweiten Parameter....
Wenn also die gefundene Stelle durch mehrzeilige Teile ersetzt werden soll, muss etwas mehr passieren....bei Interesse poste ich hier gerne den Code.
-
dann lass mal sehen ...
-
ich traue mich fast nicht diese Code zu Posten....so schwachsinnig und umständlich mutet er an. Aber er ist der einzige der zu dem von mir gewünschten Ergebniss führte:
also, erste Schleife:
.
.
.
Set rtnav = body.CreateNavigator
crlfcount = 0
pos = 0
If rtnav.FindFirstString(CRLF , RT_FIND_CASEINSENSITIVE) Then
Do
crlfcount = crlfcount + 1
Loop While rtnav.FindNextString(CRLF , RT_FIND_CASEINSENSITIVE)
End If
.
.
.
diese holt nur die anzahl der stellen die es zu ersetzten gilt.
das eigendliche ersetzen erfolgt dann über eine doppelte schleife (da es kein FindNthString gibt) :
.
.
For i = 0 To crlfcount -1
If rtnav.FindFirstString(CRLF , RT_FIND_CASEINSENSITIVE) Then
While pos < i
Call rtnav.FindNextString(CRLF , RT_FIND_CASEINSENSITIVE)
pos = pos + 1
Wend
End If
Call body.BeginInsert( rtnav,True)
Call body.APpendText(param)
Call body.EndInsert
Next
.
.
.
----
da ich diese Teile aus einem größeren Zusammenhang kopiert habe ,sind sie in dieser Form nicht getestet. Ich hoffe aber das sie das Prinzip zeigen.
Nämlich das es für jede Position immer wieder mit einem FindFirstString beginnt...und dann mit FindNextString zum Punkt gehangelt wird. (da ja, wie ich oben anmerkte, FindNextString nur noch "habe fertig" zurückliefert wenn vorher ein CHR(13) eingefügt wurde, obwohl es ggf. noch mehr zu finden gäbe,
-
Wobei man damit jetzt wieder beim manuellen Hangeln angelangt wäre. Das hatten wir doch schon.
Hmm, wenn man die beiden Methoden kombinieren könnte. So nach dem Motto alles was einfach ist mit FindAndReplace und den Rest dann mit der Methode von Roalf.
-
@Roalf:
Danke für die Code Snippets; werde ich testen und sehen, wie ich das in den bestehenden Code zu integrieren.
Habe mir überlegt, beim Stamp Documents Feld noch ein paar Varianten einzubauen:
test0 | Hallo Welt ( auch multiValue möglich mit Hallo;Welt;Tolles;Wetter;heute )
+test1 | Hallo Welt
#test2 | 1
test3 | <<FieldName>>
test0 | Hallo Welt:
wie ReplaceItemValue; erstellt das Feld, wenn es noch nicht vorhanden ist und fügt den String "Hallo Welt" in das Feld ein.
+test1 | Hallo Welt
Hängt den String "Hallo Welt" an das bestehende Feld an
#test2 | 1
addiert den Wert 1 zu dem bestehenden Wert in Feld test2
test3 | <<FieldName>>
Hole einen Wert auf dem Feld FIELDNAME und schreibt diesen in Feld test3
wobei auch Kombinationen möglich sind; wie z.B.
#test3 | <<FIELDNAME>>
addiere den Wert aus FIELDNAME zu Feld test3
Keine Ahnung, ob man so etwas braucht, aber besser man hat, als man hätte ;D