CleanCode Perl Libraries
Multi-Lingual Library Maintainability
available: Perl not available: Java not available: JavaScript not available: Certified
not available: Testable
not available: Standalone
available: Diagnostic


CGI::PageSequencer - Creates navigation between static or dynamic web pages.


  use CGI::PageSequencer;
  # This first example usage outlines how to hook up the sequencer
  # in your top level script to navigate between web pages.
  $sequencer = CGI::PageSequencer->new($seqFile, $libMgr, $nodeName);
  if ($seq->success()) {
    if ($seq->isStartNode()) {
    elsif ($actionName) {
      if (!$seq->isValidateLink($actionName)) {
        # always go to next node
      else {
        # go to next node IF valid data; otherwise show errors
        $seq->advanceNode($actionName) if ...
    else { # no actionName; just use current node
    if ($seq->getExitUrl()) { # use redirect url, if any
    else { # generate page for current node
      ... print ...
  # lower level example usage (such as used by CGI::PageGenerator)
  $fieldRef = $seq->getFields();
  foreach $field (@$fieldRef) { ... }
  $fieldRef = $seq->getFormattedFields();
  foreach $field (@$fieldRef) { ... }
  $linkList = $seq->getLinks();
  foreach $linkName (@$linkRef) { ... }


Perl5.005, Config::General, Data::Dumper, Data::Diagnostic, Data::Handy, File::Handy


This module provides a data-driven mechanism for automating website creation statically or dynamically. For dynamic web page creation, you create a sequencing file which describes the contents of each web page and the connections between web pages. Also, you must provide a LibraryMgr which defines the characteristics of each field you have specified in your sequencing file. Finally, you need an instrumented CGI script which creates and uses an instance of CGI::PageSequencer. An outline of this is shown in the Synopsis section.

PageSequencer is designed to work in conjunction with PageGenerator to create dynamic web pages and navigate amongst them. In particular (using a LibraryMgr), you may create a complete web page containing a form for the user to fill out by simply specifying a field list in the configuration file for PageSequencer. It will then ask PageGenerator to create the page and serve it up to the user. Once filled out by the user, PageSequencer will ask PageValidator to validate the fields, then either send the page back to the user for corrections, or send the follow-on page to the user. Besides simple field handling, you may also specify plugins in the configuration file that will perform ancillary processing. A typical example is a feedback page: collect input from a user, then send email to a system administrator. The CleanCode Contact Us web page uses this precise mechanism. The initial contact page asking the user to fill in information and the subsequent page confirming what has been sent require no coding: you just specify a list of fields in the configuration file, as mentioned, and define the characteristics of those fields in the dictionary. The only bit of coding is to actual assemble and send the piece of e-mail.

Bootstrapping a Configuration File

Here's complete code for a bootstrapping example, to see if you've created a good sequencer file.

  use Data::Diagnostic;
  use CGI::PageSequencer;
  my $configFile = shift @ARGV || "";
  die "$0: '$configFile' not found" unless $configFile && -f $configFile;
  my $seq = CGI::PageSequencer->new($configFile, undef, "START");
  print "Sequencer result: " . ($seq->success()? "OK" : "FAILED") . "\n\n";
  print "========= Nodes scanned =========\n";
  print $seq->dump() . "\n\n";
  print "========= Ordered nodes =========\n";
  print $seq->dump(1) . "\n";

If you call this script, and your sequencer file sequence.conf, invoke the script with either of these: sequence.conf 1 sequence.conf "CGI::PageSequencer"

The final argument is a diagnostic mask, which will produce different output. Try it with the sample sequencer configuration file shown below. If you receive any errors, then you haven't hooked up all the settings right; typically, a path is most common. (You will receive a warning about a missing library manager, which can be ignored for this test.)

Configuration File Definition

The configuration file uses an Apache-compatible syntax. A definition line consists simply of name=value. (You may optionally use whitespace instead of the equals sign.) The octothorp (#) is the inline comment character; any text following it is ignored, as are blank lines.

Top-level elements

connector = link-name

templatePath = directory-name

template = file-name

templateFatal = file-name

defaultFieldWidth = integer

defaultFieldHeight = integer

defaultFieldMaxlen = integer

pageTitle = string


The top-level elements are global defaults. If not explicitly provided in node-level elements, these will be inherited. Additionally, you may specify any arbitrary defaultxxx property you wish, then access them via the getDefault method.

Node-level elements

field = field-name | field-picture


plus all of the top-level elements...

Each node is defined with a <Node name>...< /Node> bracket pair. Within the brackets, define any of the elements shown above, each on a separate line. Multiple field elements may be used, with different clauses. Multiple link elements may also be used. For both fields and links, the order you have them in your file determines the order they will appear on your web page. You must have a node named START as your initial node, and a node named END as your final node. Intermediate nodes may use any other names you choose. Any top-level definition may be overridden with a node-level definition. This override acts only on the node which defines it.

name = link-name

gotoNode = node-name

gotoUrl = url

validate = boolean

processObject = plugin-class-name

Each link is defined with a <Link>...< /Link> bracket pair. Only one of gotoNode or gotoUrl are permitted in each link block. The START and END virtual nodes must each have a link named TRANSIT. The START node's TRANSIT typically specifies a gotoNode clause indicating your first actual node. The END node's TRANSIT typically specifies a gotoUrl clause indicating a new URL to load at the end of your sequence of pages. The validate element should have a true clause for those links which should invoke the CGI::PageValidator before transiting to the link destination.

The processObject element should specify a complete plugin class name, e.g. "CGI::PagePlugin::FormMail". The plugin must implement the following interface. (1) The constructor takes two parameters, an array reference listing the field names to process, and an an InputOptions object. (2) A no-argument process method to do whatever processing you wish.

Configuration File Sample

        connector = Next
        template = generic.thtml
        templateFatal = fatal.thtml

        <Node START>
                        name = TRANSIT
                        gotoNode contactInfo
        <Node contactInfo>
                pageTitle=Contact Information
                field FirstName
                field LastName
                field Address
                field City
                field PostCode
                        gotoNode subscriptionDetails
                        validate = 1
                        gotoUrl http : //
        <Node subscriptionDetails>
                pageTitle=Subscription Information
                template = subs.thtml
                field CCName
                field CCNumber
                field CCType
                field CCExpiry
                        gotoNode END
                        gotoNode contactInfo
                        gotoUrl http : //
        <Node END>
                        name = TRANSIT
                        gotoUrl http : //



Current version of this class.



PACKAGE->new(seqPath, seqName, libMgr, nodeName)

Returns a newly created object for the specified sequence file and library manager, and sets the current node. If a nodeName is not specified, the initial START node is used.


seqPath - string; path to directory containing sequence files

seqName - string; sequence name for this particular sequence; used to select a corresponding sequence specification file, having the path "seqPath/seqName.conf".

libMgr - LibraryMgr object

nodeName - optional; string; node to use in subsequent method calls


a newly created object




Indicates whether sequencer initialization was successful.


boolean indicating whether sequencer initialization was successful.



Return array reference to list of field name strings for the current node. This list of fields specifies the required fields for the node, so may be used to verify that all required fields have been supplied. Also, each field name may be used as an index into an element library as provided by LibraryMgr, for example.


array reference to list of field names for the current node.



Returns the current sequence name, extracted from the PATH_INFO portion of the URL, having the general form: .../cgi-bin/program/sequenceName/nodeName


name of the current sequence



Returns the current node name, extracted from the PATH_INFO portion of the URL, having the general form: .../cgi-bin/program/sequenceName/nodeName


name of the current node




exitUrl for the curent node, if any




name of the current link.


Return hash reference to list of links for the current node. Each link in the list defines a named connector from the current node to another node or an external URL. The hash consists of (connector-name, path) pairs. A path is itself a hash containing either a gotonode key or a gotourl key, defining the target of the connector. So here is one way to create a URL for each connector:

  foreach my $link (keys %$linkRef) {
      my $buttonHash = $linkRef->{$link};
      if ($buttonHash->{gotonode}) {
        $url = $cgi->url(-relative=>1) . "/" . $buttonHash->{gotonode};
      elsif ($buttonHash->{gotourl}) {
        $url = $buttonHash->{gotourl};
      # process $url here...

hash reference to links for the current node.



Returns a boolean indicating whether the specified link should be validated. If the current node does not contain a link of the specified name, returns false (0).


link - a link object (one element of the array returned by getLinks).

name - a name of a link button.


boolean indicating whether the specified link should be validated.



Returns the path name for template files for the current node, if defined; otherwise, returns the global template path name, if defined; otherwise, returns undef.


name of path to template files



Returns the template file name for the current node, if defined; otherwise, returns the global template file name, if defined; otherwise, returns undef. In the sequence file, templates should be specified as a pure file name with no path prepended. The path is specified with the templatePath element.


name of template file



Returns a template file name, just like getTemplate. This one is used in case of fatal errors, (where you have determined that the regular web page could not be generated). In the sequence file, templates should be specified as a pure file name with no path prepended. The path is specified with the templatePath element.


name of fatal template file



Returns a connector name, i.e. the name of the link which traverses the node set from the START node to the END node. In a typical scenario this might be the Next link. It does not have to be unique. Note that if you also have a Back link, it may also traverse all your nodes, but in the opposite direction.


name of connector



Returns a named default value. Pre-defined ones include fieldWidth, fieldHeight, and fieldMaxlen. In your sequence file, these would be denoted as defaultFieldWidth, defaultFieldHeight, and defaultFieldMaxlen, respectively. Retrieve each with the pre-defined name, e.g. getDefault("fieldWidth") returns the value of defaultFieldWidth from the file. Also, for any arbitrary field xyz, call getDefault("xyz") to retrieve the defaultXyz property value.


defaultName - string


value of specified default



Identifies whether current node is the START node.


boolean indicating whether current node is the START node.



Identifies whether current node is the END node.


boolean indicating whether current node is the END node.



Performs desired processing for this node via a plugin. Loads the plugin class specified for this node, instantiates an object of that class, invokes its process method, then stores its output from its output method (as a single string).


inputData - an InputOptions object;



The processNode method processes the plugin for this node and stores its output in an instance variable; this method retrieves that output.


output of the node plugin



Returns next node or a false value if no more nodes, as specified by the connector parameter.


connector - optional; string; name of Link field in the configuration file which connects to the next node in a normal progression (e.g. if currently at "Step 1" and pressing Next goes to "Step 2", then Next is the connector). If no connector is specified, the value defined in the configuration file will be used.


Returns next node or a false value if no more nodes.



Returns textual dump of sequencer semantics as defined by the configuration file.


traverse - optional; boolean. If true, lists nodes in traversal order, beginning at the START node, progressing towards the END node, based on the connector specification in the configuration file. If false, lists nodes in sorted order and verifies semantics of all nodes.


String; representation of sequencer semantics.




Michael Sorens


$Revision: 8 $ $Date: 2006-12-19 21:13:43 -0800 (Tue, 19 Dec 2006) $


CleanCode 0.9


CGI::PageGenerator, CGI::PageValidator


Hey! The above document had some coding errors, which are explained below:

Around line 398:

=back doesn't take any parameters, but you said =back -- end of CONSTRUCTOR section

Around line 956:

=back doesn't take any parameters, but you said =back -- end of METHOD section

CleanCode Perl Libraries Copyright © 2001-2013 Michael Sorens - Revised 2013.06.30 Get CleanCode at Fast, secure and Free Open Source software downloads