
For one of my websites I wanted to create static HTML but keep headers, footers and other tokens the same between pages.
For a few pages "copy and paste" was all I needed, but as the site grew it became a time consuming process to change every page each time I wanted to changed some links in the header.
One option is to use Ant's Filterset. This is an excellent solution, especially for managing environmentally specific property files.
I wanted more control (specifically I wanted to ignore subversion .svn directories), so I ended up writing my own solution in Perl.
To reference a template, us the uppercase name of the HTML file in the templates directory as the variable name. For example <TMPL_VAR NAME=FOOBAR> refers to templates/foobar.html
The code ignores subversion files. i.e. anything in .svn is not copied over to target.
Only templates ending in ".html" are used. For source files, the code checks to see if the file is text or binary. Only text files are merged. Binary files are copied over to target unchanged.
If the target directory already exists, the code renames it to target_old. If target_old exists, the code errors and stops, so remove the target_old directory if it exists before running build.pl
The code will work with multiple levels of directories underneath "source"
Your file structure should look like this:
Working_directory/
build.pl - the perl script below
templates/ - directory containing HTML fragments, such as foobar.html
source/ - directory containing HTML pages such as index.html
#!/usr/bin/perl -w use strict; use HTML::Template; # Comes with standard build use File::Find; use File::Copy; my %templates; my $templateDir = "templates"; my $sourceDir = "source"; my $destDir = "target"; sub main { # Read in the templates find(\&processTemplate, $templateDir); # Create target directory die "Please remove target_old directory first" if ( -d $destDir.'_old'); if (-d $destDir ) { rename($destDir ,$destDir.'_old') or die "Failed to rename $destDir to ${destDir}_old\n"; } # Go through source find({wanted => \&processSourceContext, no_chdir => 1 } , $sourceDir ); print "Completed.\n"; } sub readFile { # $_ is path/filename # Returns file contents open FILE, "<$_"; my $fileContents = do { local $/; <FILE> }; close FILE; return $fileContents; } sub processTemplate { my $basename = $_; # basename my $filename = $File::Find::name; # Full path if ($filename =~ /.html$/ && ! ( $filename =~ /\.svn/ ) ) { # Name of this template will be the file basename withouth the extension my $templateName = $basename; $templateName =~ s/\.[\w\d]+$//; $templateName = uc($templateName); print "Processing template $templateName\n"; $templates{$templateName} = readFile($filename); } } sub processFile { # $_ is path/file # open the html source my $template = HTML::Template->new(filename => $_, die_on_bad_params => 0); # Process the templates while ((my $key, my $value) = each(%templates)){ print "Using template $key\n"; $template->param($key => $value); } $_ = sourceToTarget($_); open (FILE,">$_") or die "I cannot open $_ to write.\n"; print FILE $template->output; close(FILE); } sub processSourceContext { # $_ is path/file if ( /\.svn/ || /^\.+$/ ) { print "Ignoring $_\n"; } elsif ( -d ) { # Create the same directory in the target print "Creating directory $_\n"; mkdir(sourceToTarget($_)) or die $!; } elsif ( -T ) { # Text File print "Processing $_\n"; processFile($_); } elsif ( -B ) { # Binary file print "Copying binary file $_\n"; my $source=$_; copy($source, sourceToTarget($source)) or die "Copy failed: $!"; } else { # Anything else... die "Encountered $_ and I do not know what to do with it"; } } sub sourceToTarget { # Returns target directory/file structure, given source directory/file structure s/$sourceDir/$destDir/; return $_; } main();