use strict; package HtmlBlocks; #---------------------------------------------------------------------- # Extract named blocks from file and put in a hash sub extract { my ($input) = @_; return _parse ($input, Extracter->new()); } #---------------------------------------------------------------------- # Substitute html in hash for blocks with same name in input sub substitute { my ($input, $html) = @_; return _parse ($input, Substituter->new ($html)); } #---------------------------------------------------------------------- # Wrap hash items in comments sub wrap { my ($hash) = @_; while (my ($key, $value) = each %$hash) { $hash->{$key} = "\n$value\n\n"; } return $hash; } #---------------------------------------------------------------------- # Parse named blocks in html file sub _parse { my ($input, $object) = @_; my @token = split (/()/i, $input); foreach my $token (@token) { if ($token =~ //) { $object->enter ($token, $1); } elsif ($token =~ //) { $object->leave ($token, $1); } else { $object->mid ($token); } } return $object->disgorge; } package Extracter; #---------------------------------------------------------------------- # Initialize state sub new { my ($pkg) = @_; my $self = {}; $self->{html} = {}; $self->{stack} = []; return bless ($self, $pkg); } #---------------------------------------------------------------------- # Push new block on the stack sub enter { my ($self, $token, $id) = @_; push (@{$self->{stack}}, $id); $self->mid ($token); } #---------------------------------------------------------------------- # Remove block from the stack and add to hash sub leave { my ($self, $token, $newid) = @_; my $oldid = pop (@{$self->{stack}}); die "Mismatched ids: $oldid and $newid\n" if $newid ne $oldid; $self->{html}{$oldid} .= $token; $self->mid ($token); } #---------------------------------------------------------------------- # Add token to all blocks on the stack sub mid { my ($self, $token) = @_; foreach my $id (@{$self->{stack}}) { $self->{html}{$id} .= $token; } } #---------------------------------------------------------------------- # Return hash sub disgorge { my ($self) = @_; return $self->{html}; } package Substituter; #---------------------------------------------------------------------- # Initialize structure sub new { my ($pkg, $html) = @_; my $self = {}; $self->{stack} = []; $self->{html} = $html; $self->{text} = ''; return bless ($self, $pkg); } #---------------------------------------------------------------------- # Handle new named block sub enter { my ($self, $token, $id) = @_; if (@{$self->{stack}}) { push (@{$self->{stack}}, $id); } elsif (exists $self->{html}{$id}) { $self->{text} .= $self->{html}{$id}; push (@{$self->{stack}}, $id); } else { $self->{text} .= $token; } } #---------------------------------------------------------------------- # Remove named block from stack sub leave { my ($self, $token, $newid) = @_; if (@{$self->{stack}}) { my $oldid = pop (@{$self->{stack}}); die "Mismatched ids: $oldid and $newid\n" if $newid ne $oldid; } else { $self->{text} .= $token; } } #---------------------------------------------------------------------- # Add token to output text if we are not in a named block sub mid { my ($self, $token) = @_; $self->{text} .= $token unless @{$self->{stack}}; } #---------------------------------------------------------------------- # Return output text sub disgorge { my ($self) = @_; return $self->{text}; } 1; __END__ =pod =head1 NAME HtmlBlocks - HTML Block extraction and substitution =head1 SYNOPSIS use HtmlBlocks; # Parse input file and substitute into template my $hash = HtmlBlocks::extract ($input); or my $hash = HtmlBlocks::wrap ($hash); my $output = HtmlBlocks::substitute ($template, $hash); =head1 DESCRIPTION This module forms the back end of a simple templating system. Regions of an html template are delimeted by special comments. The substitute subroutine replaces thes regions with the corresponding values in a hash. The extract subroutine will create a hash from an existing html file. By combining the two subroutines, you can merge the content of one page with another. So two subroutines in this module are designed to be called: =over 4 =item $hash = HtmlBlocks::extract ($input); This subroutine parses a string, extracts all the comment delimeted blocks and places them in a hash indexed by the block's id. =item $output = HtmlBlocks::substitute ($template, $html); This subroutine replaces comment delimeted blocks contained in the template string with values in a hash with the same id. The result is the resulting string. =item $hash = HtmlBlocks::wrap ($hash); As an alternative to extracting items from a web page, you can create comment delimeted blocks from an already existing hash. =back =head1 SYNTAX Comment blocks in the template are wrapped in html comments that look like where name is any identifier string. =head1 AUTHOR Bernie Simon (http://carelesshand.net) =head1 LICENSE Copyright Bernard Simon, 2005. You may use this file as you wish as long as this copyright notice is maintained.