NAME
HTML::Seamstress - dynamic HTML generation via pure HTML and pure Perl.
SYNOPSIS
# HTML
<html>
<table supply="$s->_aref($s->load_data)">
<tr> <th>name<th>age<th>weight</th> </tr>
<tr iterator="$s->{supply}->Next">
<td worker="$s->_text($s->{iterator}->{name})"> </td>
<td worker="$s->_text($s->{iterator}->{age})"> </td>
<td worker="$s->_text($s->{iterator}->{weight})"> </td>
</tr>
</table>
</html>
# Perl
use HTML::Seamstress;
HTML::Seamstress->weave(html => 'simple.html', with => 'simple.pm');
# simple.pm
package simple;
use base qw(HTML::Seamstress::Iterator HTML::Stitchery);
my @name = qw(bob bill brian babette bobo bix);
my @age = qw(99 12 44 52 12 43);
my @weight = qw(99 52 80 124 120 230);
sub new {
my $this = shift;
bless {}, ref($this) || $this;
}
sub load_data {
my @data;
for (0 .. 5) {
push @data, {
age => $age[rand $#age] + int rand 20,
name => shift @name,
weight => $weight[rand $#weight] + int rand 40
}
}
return \@data;
}
1;
DESCRIPTION
HTML::Seamstress
allows webpages to be built by serving as the bridge between experts in their respective pure technologies: HTML experts do their thing, object-oriented Perl experts do their thing and HTML::Seamstress
serves to weave the two together, traversing the pure HTML and making use of the output of Perl objects at various points in the traversal.
Its distinctive feature, unlike existing techniques, is that it uses pure, standard HTML files: no print-statement-laden CGI scripts, no embedded statements from some programming langauge, and no pseudo-HTML elements. Code is cleanly separated into a separate file. What links the two together are semantic attributes for HTML elements.
In model-view-controller terms, the HTML is the view. Seamstress is the controller, making calls to Perl methods to retrieve model data for inclusion in the view.
In HTML::Seamstress
the model classes are completely view and controller independant, and are thus use-able outside of HTML and more importantly, unit-testable outside of Perl.
Seamstress knows what Perl methods to call and when by the looking up specific attributes within a tag that are special to it. The attributes are supply
, iterator
, and worker
tags.
A
worker
attribute is used when actual "work" is going to be done on the HTML file. This work is usually simple such as_text
, which sets the content aspect of theHTML::Element
to some text. The others are listed in the manpage forHTML::Stitchery
.A
supply
attribute is called for side-effect. It creates a store of data for use byiterator
andworker
tags. Note that this creation may be actual or via a Perltie
.HTML::Seamstress
automatically stores the results ofsupply
attribute evaluation in the page object under$s-
{supply}> for later reference.An
iterator
attribute is used to pull records from asupply
store previously created.HTML::Seamstress
automatically stores the results ofiterator
attribute evaluation in the page object under$s-
{iterator}> for later reference.
Companion modules
HTML::Seamstress
has one simple job as described above. A number of other modules, work to make this a complete suite for other HTML-based tasks:
HTML::Stitchery
provides a number of useful "stitches" to be automatically woven into HTML files. These stitches are nothing more than object methods. For practical examples of many common dynamic HTML generation tasks such as dynamic table generation, language localization, database connectivity, conditional HTML, and so forth see its documentation. But in doing so, note well that all of the above tasks are implemented as Perl object methods and incur the minal class attribute adulteration of the HTML. In fact, the actual attribute to be used can be configured by setting$worker_attr
,$supply_attr
,$iterator_attr
inHTML::Seamstress
.CGI::Seamstress
is a derived class ofHTML::Seamstress
,HTML::Stitchery
andCGI.pm
. All capabilities of each of these individual technologies are offered to the programmer while placing no burden on the HTML designer. It, ahem, isn't written yet. But it does sound good and orthogonal, doesn't it? :)Apache::Seamstress
is a derived class ofHTML::Seamstress
,HTML::Stitchery
,CGI.pm
, andApache::Request
. And it isn't written yet either. Sigh.
Sample usage of HTML::Seamstress
The t/
directory of _HTML::Stitchery_ (not HTML::Seamstress) contains a large number of examples. Further examples are in the CGI::Seamstress and Apache::Seamstress directories.
This, and other small snippets of documentation are taken from Paul J. Lucas' HTML Tree distribution (http://homepage.mac.com/pauljlucas/software/html_tree), which CHTML::Seamstress
was based on but changed due to experience.
The HTML File
The file for a web page is in pure HTML. (It can also contain JavaScript code, but that's irrelevant for the purpose of this discussion.) At every location in the HTML file where something is to happen dynamically, an HTML element must contain a CLASS
attribute (and perhaps some "dummy" content). (The dummy content allows the web page designer to create a mock-up page.)
For example, suppose the options in a menu are to be retrieved from a relational database, say the flavors available on an ice cream shop's web site. The HTML would look like this:
<SELECT NAME="Flavors" SUPPLY="$s->query_flavors">
<SPAN ITERATOR="$s->{supply}->next_flavor">
<OPTION WORKER="$s->_text($s->{iterator}->{flavor}" VALUE="0">
Tooty Fruity
</OPTION>
</SPAN>
</SELECT>
query_flavors
, next_flavor
, and the worker will be used to generate HTML dynamically. The values of the attributes
attributes can be any Perl code as long as they agree with those in the code file (specified later).The text "Tooty Fruity" is dummy content.
The query_flavors
SUPPLY
will be used to perform the query from the database; next_flavor
will be used to fetch every tuple returned from the query and to substitute the name and ID number of the flavor.
The Code File
The associated code file in Perl in specified via the weave
configuration option of HTML::Seamstress
.
The implementation of the query_flavors()
and next_flavor()
methods shall be presented in stages.
The query_flavors()
method begins by getting its arguments as described above:
sub query_flavors {
my $this = shift;
A copy of the database and statement handles is stored in the object's hash so the next_flavor()
method can access them later:
$this->{ dbh } = DBI->connect( 'DBI:mysql:ice_cream:localhost' );
$this->{ sth } = $this->{ dbh }->prepare( '
SELECT flavor_id, flavor_name
FROM flavors
ORDER BY flavor_name
' );
$this->{ sth }->execute();
Finally, the method returns true to tell HTML::Seamstress
to proceed with parsing the SELECT
element's child elements if any rows were returned from the query.
return $this->{sth}->rows;
}
The next_flavor()
method begins identically to query_flavors()
:
sub next_flavor {
my $this = shift;
The next portion of code fetches a tuple from the database. If there are no more tuples, the method returns false. This tells HTML::Seamstress
not to emit the HTML for the OPTION
element and also tells it to stop looping:
my( $flavor_id, $flavor_name ) = $this->{ sth }->fetchrow();
unless ( $flavor_id ) {
$this->{ sth }->finish();
$this->{ dbh }->disconnect();
return 0;
}
The code also disconnects from the database. (However, if Apache::DBI
was specified, the disconnect()
becomes a no-op and the connection remains persistent.)
Finally, the method returns true to tell HTML::Seamstress
to emit the HTML for the OPTION
element now containing the dynamically generated content: return $flavor_name;
}
1;
How this software differs from Paul J. Lucas' HTML_Tree
In concept, Seamstress and Lucas' HTML_Tree (call it ltree) are the same, with Seamstress being developed after usage of ltree. However, there are some technical differences between the packages:
HTML::Seamstress
parses the HTML using SBURKE's HTML::Tree distribution. SBURKE's HTML parser is written in C and Paul Lucas' HTML parser is written in C++, so they are both fast.in ltree, a .pm file must be associated with your HTML file and you must write your own constructor.
Both of these steps are optional with
HTML::Seamstress
. You can always inherit theHTML::Stitchery
constructor if you want and if you have an HTML file that you don't wantHTML::Seamstress
dhtml in, then you don't have to have a dummy .pm file, simply omit theusing
argument to HTML::Seamstress'weave
method... actually at the moment I require a file a well, but this restriction and automatic common page objects will be made available in a later version.method lookups in ltree are done through two mechanisms: a hash called
%function_map
:% function_map = ( href_id => \&sub_href_id , .... ) ;
and the
class_map
attribute of your required constructor in your required .pm file.HTML::Seamstress
simply relies of Perl object-oriented single dispatch. But it could do multiple-dispatch as well.each object method had to do its own argument splitting in ltree:
# ltree example - note API is slightly different too sub sub_href_id { my ($this, $node, $class_arg, $is_end_tag) = @_; my ($method, @arg) = split '::', $class_arg;
Because
HTML::Seamstress
uses pure Perl in the attributes as opposed to a pseudo-HTML-like language, it does not have to do argument splitting but lets Perl handle that.ltree does not support traversal of infinite levels of reference nesting.
Instead it has a simple text() method which returns the key in the hash of its arguments. Because
HTML::Seamstress
uses Perl, arbitrary degrees of nesting of hashes, arrays, as well as method overloads could be supported.
AUTHOR
T. M. Brannon <tbone@cpan.org>
SEE ALSO
Paul J. Lucas' HTML Tree distribution (http://homepage.mac.com/pauljlucas/software/html_tree)
2 POD Errors
The following errors were encountered while parsing the POD:
- Around line 537:
You forgot a '=back' before '=head1'
- Around line 714:
You forgot a '=back' before '=head1'