Making complex formatstrings slightly less complex

From Gordon Paynter
DateThu, 23 May 2002 10:43:11 -0700
Subject Making complex formatstrings slightly less complex
This email describes a way that you can make complex Greenstone
formatStrings more easily. If you always use the default
formatstrings, you should ignore it. If you don't like working at the
command-line, you should probably ignore it too.


In my last email I mentioned that I no longer attempt to edit
formatstrings in the collect.cfg file. Instead, I put every
formatstring in its own file, and have a program that combines these
files into the collect.cfg file.

Why do I do this? Because you're not allowed to put newline
characters into formatstrings: they have to all be on the same line.
This gets very very ugly in my collections, which have very complex
formatstrings.

What I do instead is allow newlines in the formatstring files, and
have the merging program strip them when it rebuilds collect.cfg.


For example, in my album collection, the collect.cfg file contains the
line:

format DocumentText '<font face="Arial"> <table width="100%"
border="0"> <tr> <td align="center"> {If}{[movie], <b>Movie:</b>
/gsdl/collect/album/index/assoc/[assocfilepath]/[movie] }
{If}{[Image], <table border="0"> <tr> <td align="center" colspan="2"
background="/gsdl/collect/album/logo/top.gif"> <b>[Title]</b>
</td> </tr> <tr> <td width="120" align="right">Photographer:</td>
<td>[Photographer]</td> </tr> <tr> <td align="right">&nbsp;</td> <td
align="left">[Rights]</td> </tr> <tr> <td align="right">Location:</td>
<td><a href="/gsdlmod?c=gsarch&a=q&h=dtp&q=[Place]">[Place]</a></td>
</tr> <tr> <td align="right">Date:</td> <td>[Date]</td> </tr> <tr> <td
align="right">Size:</td> <td>[ImageWidth]x[ImageHeight] pixels</td>
</tr> <tr> <td colspan="2" align="center"> <img
src="/gsdl/collect/album/index/assoc/[assocfilepath]/[Screen]"
width="[ScreenWidth]" height="[ScreenHeight]" /> </td> </tr> <tr> <td
colspan="2" align="center"
background="/gsdl/collect/album/logo/bottom.gif"> <font
face="Arial" color="black"> <b> <a
href="/gsdl/collect/album/index/assoc/[assocfilepath]/[Thumb]">Thumbnail</a>
&nbsp;&nbsp;<a
href="/gsdl/collect/album/index/assoc/[assocfilepath]/[Screen]">Small
Image</a> &nbsp;&nbsp;<a
href="/gsdl/collect/album/index/assoc/[assocfilepath]/[Image]">Full
Image</a> </b> </font> </td> </tr> </table> } </td> </tr> </table>
</font>'

In practice, I have this formatstring stored in a file called
format.DocumentText. Here's what it looks like:

----- begin format.DocumentText -----
<font face="Arial">
<table width="100%" border="0">
<tr>
<td align="center">
{If}{[movie],
<b>Movie:</b>
/gsdl/collect/album/index/assoc/[assocfilepath]/[movie]
}
{If}{[Image],
<table border="0">
<tr>
<td align="center" colspan="2"
background="/gsdl/collect/album/logo/top.gif">
<b>[Title]</b>
</td>
</tr>
<tr>
<td width="120" align="right">Photographer:</td>
<td>[Photographer]</td>
</tr>
<tr>
<td align="right">&nbsp;</td>
<td align="left">[Rights]</td>
</tr>
<tr>
<td align="right">Location:</td>
<td><a
href="/gsdlmod?c=gsarch&a=q&h=dtp&q=[Place]">[Place]</a></td>
</tr>
<tr>
<td align="right">Date:</td>
<td>[Date]</td>
</tr>
<tr>
<td align="right">Size:</td>
<td>[ImageWidth]x[ImageHeight] pixels</td>
</tr>
<tr>
<td colspan="2" align="center">
<img
src="/gsdl/collect/album/index/assoc/[assocfilepath]/[Screen]"
width="[ScreenWidth]" height="[ScreenHeight]" />
</td>
</tr>
<tr>
<td colspan="2" align="center"
background="/gsdl/collect/album/logo/bottom.gif">
<font face="Arial" color="black">
<b>
<a
href="/gsdl/collect/album/index/assoc/[assocfilepath]/[Thumb]">Thumbnail</a>
&nbsp;&nbsp;<a
href="/gsdl/collect/album/index/assoc/[assocfilepath]/[Screen]">Small
Image</a>
&nbsp;&nbsp;<a
href="/gsdl/collect/album/index/assoc/[assocfilepath]/[Image]">Full
Image</a>
</b>
</font>
</td>
</tr>
</table>
}
</td>
</tr>
</table>
</font>
----- end format.DocumentText -----

This is not really all that simple, but it is an awful lot easier to
read and debug than the single-line version.

Anyway, if you're interested in trying it for yourself, here's the
perl script for merging. Put it in the collection's etc directory
with the collct.cfg file, and run it there. It works by 1. searching
for all the files named format.XXX (where XXX is a formatstring name);
2. truncating the collect.cfg file after the

#### DO NOT EDIT BEYOND THIS POINT ####

(if it exists); and 3. replacing newlines in the format.XXX files with
spaces and appending them to the collect.cfg file.


Here's the code:

----- begin make_cfg.pl -----
#! /usr/bin/perl

# Build a collect.cfg file by taking the existing collect.cfg file
# and appending all the formatstrings stored in "format.*" files.
# Gordon Paynter, March 2002

my $endline = "#### DO NOT EDIT BEYOND THIS POINT ####";


# Read collect.cfg and throw out the automatically generated part

my $collect_cfg = `cat collect.cfg`;
if ($collect_cfg =~ /^$endline$/m) {
$collect_cfg =~ s/ $endline.*//s;
}
$collect_cfg =~ s/s*$/ /s;
$collect_cfg .= "$endline ";


# Read the format files and append them to $collect_cfg

my ($filename, $text);
opendir(ETC, ".");
while ($filename = readdir ETC) {

next unless ($filename =~ /^format./);
next if ($filename =~ /~$/);

# read file and get rid of newlines and make sure single-quotes are
escaped
$text = `cat $filename`;
$text =~ s/s+/ /g;
$text =~ s/^ //;
$text =~ s/ $//;
$text =~ s/([^\])'/$1\'/g;

# update $collect_cfg file with this formatstring
$filename =~ s/^format.//;
$collect_cfg .= "format $filename '$text' ";
}

# Update the collect.cfg file

system("mv collect.cfg collect.cfg.backup");
open(CFG, ">collect.cfg");
print CFG $collect_cfg;
----- end make_cfg.pl -----


As an aside, Stef, how hard would it be to allow nested {If}
constructs in formatstrings? I would really like to optionally
display [Description] metadata for my Images, but I can't because they
are wrapped in the {If}{[Image],...} construct.


Gordon