package HTML::XHTML::Lite; use 5.006; use strict; use warnings; require Exporter; our @ISA = qw(Exporter); # Items to export into callers namespace by default. Note: do not export # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. # This allows declaration use HTML::XHTML::Lite ':all'; # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK # will save memory. our %EXPORT_TAGS = ( 'all' => [ qw( ) ] ); our @EXPORT_OK = qw( start_page end_page getvars ); our @EXPORT = qw( start_page end_page getvars ); our $VERSION = '0.06'; # Preloaded methods go here. sub start_page { use HTTP::Date; use Time::Local; $_[0]={} unless defined $_[0]; my %p=%{$_[0]}; my $page; $p{content_type}='text/html' unless defined $p{content_type}; my $charset=(defined $p{charset} ? uc($p{charset}) : 'UTF-8'); $p{title}='Untitled Document' unless defined $p{title}; $p{dctitle}=$p{title} unless defined $p{dctitle}; $p{lang}=(defined $p{lang} ? $p{lang} : 'en'); $p{foaftitle}='FOAF' unless defined $p{foaftitle}; if ($p{feed}) { $p{feedtype}="application/rss+xml" unless defined $p{feedtype}; $p{feedtitle}="RSS Feed for $p{title}" unless defined $p{feedtitle}; } my $now=time2str(time()); my $expires=(defined $p{expires} ? time2str(iso2time($p{expires})) : $now); unless ($p{isfile}) { $page.="Expires: $expires\n"; $page.="Date: $now\n"; $page.="Content-type: $p{content_type}; charset=$charset\n\n"; } $page.="\n" unless $p{noxml} || $p{nohead}; $page.="\n" unless $p{nodoctype} || $p{nohead}; $page.=< $p{title} EOT $page.="\n" if defined $p{description}; $page.="\n" if defined $p{creator}; $page.="\n" if defined $p{identifier}; $page.="\n" if defined $p{subject}; $page.="\n" if defined $p{rights}; $page.="\n" if defined $p{created}; $page.="\n" if defined $p{modified}; $page.="\n" if defined $p{date}; if (defined $p{legacy} && defined $p{description} && defined $p{subject}) { my $kwds=$p{subject}; $kwds=~s/;/,/g; $page.="\n"; $page.="\n"; } $page.="\n" if defined $p{csssrc}; $page.="\n" if defined $p{css}; $page.="\n" if defined $p{feed}; $page.="\n" if defined $p{foaf}; $page.=$p{extras} if defined $p{extras}; $page.="\n"; if (defined $p{body}) { $page.=$p{body}; my %footp=%p; $footp{string}=1; $page.=end_page(\%footp); } if ($p{string}) { return $page; } else { print $page; } } # sub end_page { my $page; $_[0]={} unless defined $_[0]; my %p=%{$_[0]}; $page.="\n\n"; if ($p{string}) { return $page; } else { print $page; } } sub iso2time { $_[0] =~ /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/ or return undef; return timelocal($6,$5,$4,$3,$2-1,$1-1900); } sub getvars { # A 'Lite' version of CGI.pm's param function # Returns a reference to a hash of arrays of # name/value pairs. my (@nvps,%vars); # Look after anything coming from a # POST form if (lc($ENV{REQUEST_METHOD}) eq 'post') { read(STDIN, my $postdata, $ENV{CONTENT_LENGTH}); push(@nvps,split(/&/,$postdata)); } # Pick up anything passed through the # query string, either by a GET form # or direct by URI my $qs=$ENV{QUERY_STRING}; $qs=~s/&/;/g; push(@nvps,split(/;/,$qs)); foreach my $nv (@nvps) { my @a=split(/=/,$nv); $a[0]=~tr/+/ /; $a[0]=~s/%([\da-f][\da-f])/chr(hex($1))/egi; $a[1]="" unless defined $a[1]; $a[1]=~tr/+/ /; $a[1]=~s/%([\da-f][\da-f])/chr(hex($1))/egi; push @{$vars{$a[0]}},$a[1]; } return %vars; } 1; __END__ # Below is stub documentation for your module. You'd better edit it! =head1 NAME HTML::XHTML::Lite - Light-weight Perl module for XHTML CGI applications =head1 SYNOPSIS use HTML::XHTML::Lite; start_page({ title=>'my_title', description=>'my_description', ... }); OR pass a reference to a hash: start_page(\%my_page_data); end_page(); my %vars=getvars(); =head1 DESCRIPTION This module provides a light-weight alternative to the Perl built-in, CGI.pm, for those who wish for an easy way to produce a well-formed XHTML , with Dublin Core metadata. A function to create a footer is provided for completeness and it is even possible to provide body text to return a complete document. Provision is made for the inclusion of links to RSS (or other) feeds and FOAF data. The 'extras' property allows for the insertion of arbitrary elements into the document header. In addition to the generation of XHTML, the function getvars() is included to populate a hash with data from the query string and POST data. This is an unsophisticated equivalent to CGI.pm's $q->para('xyz') functionality and does NOT work with forms where enc="multipart/form-data" - in other words, forms that upload files. You will need to use CGI.pm to handle these until such time as that functionality is added to this module. The aim of this module is to help produce content that is both accessible and machine-parseable. One of the methods of start_page(), nodoctype=>1, is provided purely for the purpose of being able to leave out required components to check that any validation systems being used are actually working. =head2 FUNCTIONS =head3 start_page() =head4 Example use strict; use HTML::XHTML::Lite; start_page({ title=>'My Web Page', description=>'About My Web Page', creator=>'Matthew Smith', identifier=>'http://www.mss.cx', foaf=>'http://www.mss.cx/foaf.rdf', foaftitle=>'FOAF data', }); =head4 Methods string Return the XHTML created as a scalar variable; the default behaviour is to print the XHTML to STDOUT or the currently selected handle. my $foo=start_page({string=>1, ....., }); isfile Target is a file, so we don't want to create any headers. This example writes to a file, without any headers. open (OUT,">foo.out"); select OUT; start_page({isfile=>, ....., }); select STDOUT; close OUT; legacy In addition to the Dublin Core dc.description and dc.subject, "legacy" metadata, description and keywords, are inserted. The description is a straight copy of dc.description and keywords is dc.subject, with the semicolons (;) replaced by commas (,). start_page({ legacy=>1, description=>$description, subject=>$subject, ....., }); nodoctype Produce a "broken" document with no Doctype declaration. This should only be used for test purposes. noxml Do not put the processing instruction at the start of the document. nohead Combines nodoctype and noxml methods. =head4 Properties title The title of the page; defaults to 'Untitled Document' if not provided. dctitle This property allows for dc.title to take a different value to the page title; defaults to the page title if not provided. identifier Value for dc.identifier description Value for dc.description subject Value for dc.subject rights Value for dc.rights creator Value for dc.creator created Value for dc.date.created (ISO8601 format) updated Value for dc.date.updated (ISO8601 format) date Value for dc.date (ISO8601 format) lang Default page language (defaults to 'en') charset Page character set (defaults to 'utf=8') content_type MIME type for the document - defaults to text/html but other values, such as application/xml, may be used. expires Date and time for the expiry date in the HTTP header (ISO8601 format). As this module was written for CGI applications where data returned was seldom the same, this defaults to the current time, thus immediate expiry. css CSS to be included in the document header; takes prececence over csssrc styling instructions, if both css and csssrc are used. For more complex situations where more flexibility is required, it is best to provide any CSS elements through the 'extras' property. csssrc URI of an external CSS file feed URI of an RSS (or other) feed feedtype MIME type of feed - defaults to application/rss+xml feedtitle Title for feed - defaults to "RSS Feed for [page title]" foaf URI of a FOAF document; MIME type is provided as application/rdf+xml foaftitle Title for FOAF document - defaults to "FOAF" extras Everything else! If this module doesn't provide the property you want, just put it in here. body Providing a value for 'body' will cause an entire page to be created, the , body (as provided) and a call to end_page. =head3 end_page() Close and elements. Takes a hash ref [like start_page()] with arguments. Currently, only 'string' is supported; returns a scalar if true (value is 1). =head4 EXAMPLES end_page(); - prints "\n\n" end_page({string=>1}); - returns scalar "\n$filename") or die "Can't write to $filename: $!"; select OUT; start_page({ isfile=>1, title=>$title, description=>$description, subject=>$subject, creator=>$creator, created=>$created, updated=>$updated, rights=>$rights, identifier=>$identifier, csssrc=>$stylesheet, body=>"

$title

", }); select STDOUT; close OUT; sub ui { my ($prompt,$def)=@_; $prompt.=" [$def]" if defined $def; $prompt.=':'; print $prompt; $_=; chomp; if (defined $def) { return $_ ? $_ : $def; } else { return $_; } } =head1 SEE ALSO A web page for this module may be found here: http://www.mss.cx/xhtmllite/ The alternative: man CGI.pm Dublin Core Metadata: http://www.dublincore.org XHTML Specification: http://www.w3.org/TR/xhtml1/ =head1 AUTHOR Matthew Smith, smiffy@cpan.org Matthew welcomes feedback and suggestions regarding this module. =head1 COPYRIGHT AND LICENSE Copyright (C) 2005 by Matthew Smith This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.5 or, at your option, any later version of Perl 5 you may have available. =cut