HTML::XHTML::Lite - Light-weight Perl module for XHTML CGI applications


HTML-XHTML-Lite documentation Contained in the HTML-XHTML-Lite distribution.

Index


Code Index:

NAME

Top

HTML::XHTML::Lite - Light-weight Perl module for XHTML CGI applications

SYNOPSIS

Top

  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();

DESCRIPTION

Top

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 <head></head>, 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.

FUNCTIONS

start_page()

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',
	});

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 <?xml ... ?> processing instruction at
   the start of the document.

   nohead	Combines nodoctype and noxml methods.

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 <head>, body (as provided)
		and a call to end_page.

end_page()

   Close <body> and <html> elements.  Takes a hash ref [like start_page()]
   with arguments.  Currently, only 'string' is supported; returns a scalar
   if true (value is 1).

EXAMPLES

   end_page();

   - prints "\n</body></html>\n"

   end_page({string=>1});

   - returns scalar "\n</body></html\n"

DEPENDENCIES

Top

   This module requires the following modules to be installed:

   HTTP::Date
   Time::Local

   These are used to create time/date strings for the HTTP headers.




TO DO

Top

   * Inclusion of dc.accessibility, when more mature
   * Links to EARL assertions about the document
   * You tell me...

APPLICATION EXAMPLE

Top

#!/usr/bin/perl

# Programme to create XHTML template # through command line interaction.

use strict; use warnings; use HTML::XHTML::Lite;

my @tnow=localtime(time()); my $yearnow=1900+$tnow[5]; my $datenow="$yearnow-$tnow[4]-$tnow[3]";

print "C R E A T E X H T M L D O C U M E N T\n"; print "-----------------------------------------\n\n";

my $myname=ui('Your name','Fred Bloggs'); my $myname_=$myname; $myname_=~s/\s/_/g; $myname_=~s/\.//g; my $defrights="(C) Copyright $yearnow $myname"; my $filename=ui('File name',"${datenow}_${myname_}.html"); my $title=ui('dc:title','Untitled'); my $description=ui('dc:description','My Document'); my $subject=ui('dc:subject',''); my $creator=ui('dc:creator',$myname); my $created=ui('dc:date.created',$datenow); my $updated=ui('dc:date.updated',$datenow); my $rights=ui('dc:rights',$defrights); my $identifier=ui('dc:identifier',"file://$filename"); my $stylesheet=ui('Stylesheet source URI','default.css');

open (OUT,">$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=>"<h1>$title</h1>", }); select STDOUT; close OUT;

sub ui { my ($prompt,$def)=@_; $prompt.=" [$def]" if defined $def; $prompt.=':'; print $prompt; $_=<STDIN>; chomp; if (defined $def) { return $_ ? $_ : $def; } else { return $_; } }

SEE ALSO

Top

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/

AUTHOR

Top

Matthew Smith, smiffy@cpan.org

Matthew welcomes feedback and suggestions regarding this module.

COPYRIGHT AND LICENSE

Top


HTML-XHTML-Lite documentation Contained in the HTML-XHTML-Lite distribution.

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.="<?xml version=\"1.0\" encoding=\"" . lc($charset) . "\"?>\n" unless $p{noxml} || $p{nohead};
$page.="<!DOCTYPE html\n\tPUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n\t\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" unless $p{nodoctype} || $p{nohead};

$page.=<<EOT;
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="$p{lang}" lang="$p{lang}">
<head>
<title>$p{title}</title>
<link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" />
<link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" />
<meta name="DC.language" scheme="DCTERMS.RFC1766" content="$p{lang}" />
<meta name="DC.type" scheme="DCTERMS.DCMIType" content="Text" />
<meta name="DC.format" scheme="DCTERMS.IMT" content="text/html; charset=$charset" />
<meta name="DC.title" lang="$p{lang}" content="$p{dctitle}" />
EOT

$page.="<meta name=\"DC.description\" lang=\"$p{lang}\" content=\"$p{description}\" />\n" if defined $p{description};
$page.="<meta name=\"DC.creator\" content=\"$p{creator}\" />\n" if defined $p{creator};
$page.="<meta name=\"DC.identifier\" content=\"$p{identifier}\" />\n" if defined $p{identifier};
$page.="<meta name=\"DC.subject\" lang=\"$p{lang}\" content=\"$p{subject}\" />\n" if defined $p{subject};
$page.="<meta name=\"DC.rights\" content=\"$p{rights}\" />\n" if defined $p{rights};
$page.="<meta name=\"DCTERMS.created\" scheme=\"DCTERMS.W3CDTF\" content=\"$p{created}\" />\n" if defined $p{created};
$page.="<meta name=\"DCTERMS.modified\" scheme=\"DCTERMS.W3CDTF\" content=\"$p{modified}\" />\n" if defined $p{modified};
$page.="<meta name=\"DC.date\" content=\"$p{date}\" />\n" if defined $p{date};

if (defined $p{legacy} && defined $p{description} && defined $p{subject})
{
	my $kwds=$p{subject};
	$kwds=~s/;/,/g;
	$page.="<meta name=\"description\" content=\"$p{description}\" />\n";
	$page.="<meta name=\"keywords\" content=\"$kwds\" />\n";
}

$page.="<link rel=\"stylesheet\" type=\"text/css\" href=\"$p{csssrc}\" />\n" if defined $p{csssrc};
$page.="<style type=\"text/css\">$p{css}</style>\n" if defined $p{css};
$page.="<link rel=\"alternate\" type=\"$p{feedtype}\" title=\"$p{feedtitle}\" href=\"$p{feed}\" />\n" 
	if defined $p{feed};
$page.="<link rel=\"meta\" type=\"application/rdf+xml\" title=\"$p{foaftitle}\" href=\"$p{foaf}\" />\n" 
	if defined $p{foaf};
$page.=$p{extras} if defined $p{extras};
$page.="</head><body>\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;
}

} #</start_page>

sub end_page
{
	my $page;

	$_[0]={} unless defined $_[0];

	my %p=%{$_[0]};
	$page.="\n</body></html>\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!