Wiki Home

Text Merge

Namespace: People
An old Foxpro technique to merge literal text with calculated values or variables into an output text stream to disk. Probably used for hand-coded reports or mail merge letters, but is still quite useful for generating programs or other generated text output from VFP (i.e. generating HTML or XML). Far easier and less cryptic than massive string concatenation and low level file I/O via FOPEN, FWRITE, etc.

With VFP 9, \ and \\ don't like continuation to a new line, even within the << expression >>. -- Craig Roberts

Can append text blocks using TEXT/ENDTEXT to insert directly into text. Or can insert via "\" for a new line, or "\\" to append to existing line.
Don't forget that you can SET TEXTMERGE DELIMITERS TO expc,expc
Also the NOSHOW clause is a very welcome addition.
Yeah, but there's no way to find out its current value (ie, no SET function), so you can't write generic routines to reset it if you must change it. -- Randy P

? SET( "textmerge" ) works to see the off/on status. But it does not show you the current file it's using. DISP STAT will show the filename, assuming you don't have any other LLFF files open. -- df
One of the best (and original) reasons for using this command was to generate programs (especially SPR and MPR) based on templates. The SET TEXTMERGE ON/OFF command is used to control whether the expressions within delimiters are evaluated at merge time
Something to be careful about is that the text that is sent out has all lone CR (chr(13)) characters changed to CR+LF (chr(13)+chr(10)). This makes this functionality useless for outputting binary data (ie: image data) in the middle of a file.
For example spaces inserted after each < to prevent them from being interpretted as an HTML tag:
set textmerge to test.txt
* The next line produces: Chr(13)+chr(10)+'hellohi'
\\< < chr(13)+'hello'+chr(13)>>hi && {{chr(13)+'hello'+chr(13)}}hi
* The next line produces: 'one'+chr(13)+chr(10)+'two'
\\< < x>> && {{x}}
set textmerge to

If anyone knows a way to suppress this behavior, I'd be very happy to learn how! - ?wgcs
Sure! The _TEXT system variable tracks the LLFF handle of the current TEXTMERGE output file. So, you can intersperse FWRITE and FPUTS calls in with TEXTMERGE calls, such as:
= FWRITE( _TEXT, m.lcBinaryData )
-- Randy P
Thanks! That was quick, but I already rewrote it to use st=st+'new stuff' and strtofile()... I might just undo it all to regain the simplicity of <<...>> - ?wgcs
It's not just the simplicity. Performance matters too. If you're building a large file, those string concats will bog down in a hurry. Above say 5-10KB, the direct file writing approach inherent in TEXTMERGE operations will perform much better. -- Randy P
Somebody I was just introducing Text Merge to surprised me by showing that textmerge doesn't work with macro replacement. That is,
lcString = 'lnNumber'
lnNumber = 5
* This writes "The number is 5"
\The number is < < lnNumber>>
* This writes "The number is "
\The number is < < &lcString>>

But you don't need that at all - you can put
\The number is < < lnNumber>>

...or a function call, or any expression. If you really need a macro, well, just use < < eval(lcString) > > instead. -- ?Dragan Nedeljkovich

That works, or you can use EXECSCRIPT(). -- Peter Crabtree

Sept 25, 2008
What about
\The number is < < evaluate(lcString)>>

to get it to print "the number is 5"
Would that work?

[2000.09.12] The following code illustrates a bug I ran across while writing the code to generate some of the pages on my website. -- ?df

[2003.03.17] Good news! VFP8 fixes this bug.

spaces inserted after each < to prevent them from being interpretted as an HTML tag

* textmergebug.prg 11-Sep-00

* This program shows a bug when outputing large strings that
* contain embedded spaces. VFP5, VFP6 and VFP7 will erroneously
* do a word wrap function on the text which will cause a CRLF pair
* to be inserted into the output.

lcX = replicate( "abcde fghijklmnopq rstuvwxyz 0123456789 ", 100 )

set textmerge to textmergebug.txt
set textmerge on noshow
\\< < lcX>> && {{lcX}}
set textmerge off
set textmerge to

* this works around the problem
* by putting out smaller chunks of the string at a time

set textmerge to textmergeok.txt
set textmerge on noshow
do while ! empty( lcX )
   lcY = left( lcX, 512 )
   lcX = substr( lcX, 513 )
   \\< < lcY>> && {{lcY}}
set textmerge off
set textmerge to

* in the textmergebug file you will see inappropriate line breaks

modify file textmergebug.txt nowait
modify file textmergeok.txt nowait

Text Merge Class
I'm getting the error: "Textmerge is recursive. (Error 2044) The textmerge statement evaluates to an expression that, itself, performs a textmerge.", on the following code:
local lcText as String
lcText = ""
text to lcText additive textmerge noshow
	some text
	< < myFunc() > >
	more text

function myFunc()
	local lcMyFunc as String
	lcMyFunc = ""
	text to lcMyFunc additive textmerge noshow
		in function < < datetime() > >
	return lcMyFunc

This seems like a really obvious thing to do, and it's a shame it isn't working. Can anyone help or confirm there's no way to do it?
Category VFP Commands Category Code Samples
( Topic last updated: 2008.09.25 01:15:28 PM )