xmlapplication(3)

NAME

CGI::XMLApplication -- Object Oriented Interface for CGI
Script Applications

SYNOPSIS

use CGI::XMLApplication;
$script = new CGI::XMLApplication;
$script->setStylesheetPath(
"the/path/to/the/stylesheets" );
# either this for simple scripts
$script->run();
# or if you need more control ...
$script->run(%context_hash);

DESCRIPTION

CGI::XMLApplication is a CGI application class, that
intends to enable perl artists to implement CGIs that make
use of XML/XSLT functionality, without taking too much
care about specialized errorchecking or even care too much
about XML itself. It provides the power of the
XML::LibXML/ XML::LibXSLT module package for content
deliverment.

As well CGI::XMLApplication is designed to support project
management on code level. The class allows to split web
applications into several simple parts. Through this most
of the code stays simple and easy to maintain. Throughout
the whole runtime of a script CGI::XMLApplication tries to
keep the application stable. As well a programmer has not
to bother about some of XML::LibXML/ XML::LibXSLT trans
formation pitfalls.

The class module extends the CGI class. While all func
tionality of the original CGI package is still available,
it should be not such a big problem, to port existing
scripts to CGI::XMLApplication, although most functions
used here are the access function for client data such as
param().

CGI::XMLApplication, intended to be an application class
should make writing of XML enabled CGI scripts more easy.
Especially because of the use of object orientated con
cepts, this class enables much more transparent imple
mententations with complex functionality compared to what
is possible with standard CGI-scripts.

The main difference with common perl CGI implementation is
the fact, that the client-output is not done from perl
functions, but generated by an internally build XML DOM
that gets processed with an XSLT stylesheet. This fact
helps to remove a lot of the HTML related functions from
the core code, so a script may be much easier to read,
since only application relevant code is visible, while
layout related information is left out (commonly in an
XSLT file).

This helps to write and test a complete application faster
and less layout related. The design can be appended and
customized later without effecting the application code
anymore.

Since the class uses the OO paradigma, it does not force
anybody to implement a real life application with the com
plete overhead of more or less redundant code. Since most
CGI-scripts are waiting for events, which is usually the
code abstraction of a click of a submit button or an
image, CGI::XMLApplication implements a simple event sys
tem, that allows to keep event related code as separated
as possible.

Therefore final application class is not ment to have a
constructor anymore. All functionality should be encapsu
lated into implicit or explicit event handlers. Because of
a lack in Perl's OO implementation the call of a super
class constructor before the current constructor call is
not default behavior in Perl. For that reason I decided to
have special events to enable the application to initial
ize correctly, excluding the danger of leaving important
variables undefined. Also this forces the programmer to
implement scripts more problem orientated, rather than
class or content focused.

Another design aspect for CGI::XMLApplication is the
strict differentiation between CODE and PRESENTATION. IMHO
this, in fact being one of the major problems in tradi
tional CGI programming. To implement this, the XML::LibXML
and XML::LibXSLT modules are used by default but may be
replaced easily by any other XML/XSLT capable modules.
Each CGI Script should generate an XML-DOM, that can be
processed with a given stylesheet.

Pay attention: In this Document XML-DOM means the DOM of XML::LibXML and not XML::DOM!

Programflow of a CGI::XMLApplication

The following Flowchart illustratrates how CGI::XMLAppli
cation behaves during runtime. Also chart shows where spe
cialized application code gets control during script run
time.
------- CGI Script ------->|<--------- CGI::XMLApplica
tion -------
.---------------------. .--------------------.
| app-class creation |--- | event registration
`---------------------' | registerEvents()
`--------------------'
.------------------------.
| context initialization |------------'
| ( optional )
`------------------------'
.-----------------------. .------------------------.
| run() function called |--| application initialize
`-----------------------' | event_init()
`------------------------'

.--------'`------------.
/ event parameter found? _
testEvent() /
`--------.,------------'
yes
no
.------------.
.------------------.
| call event | | call
| event_*() |
event_default()
`------------'
`------------------'
.---------------------.
| application cleanup
|-----'
| event_exit()
`---------------------'

.---------'`------------.
_/ avoid XML serialization
/ skip_serialization() /
| `---------.,------------'
yes | no
.--------------------------.
| | XML generation, XSLT
| | serialization and output
| | serialization()
`--------------------------'
.---------------.
| END |-------+-------------'
`---------------'
What are Events and how to catch them
Most CGI Scripts handle the result of HTML-Forms or simi
lar requests from clients. Analouge to GUI Programming,
CGI::XMLApplication calls this an event. Spoken in
CGI/HTML-Form words, a CGI-Script handles the various sit
uations a clients causes by pushing a submit button or
follows a special link. Because of this common events are
thrown by arguments found in the CGI's query string.
An event of CGI::XMLApplication has the same name as the
input field, that should cause the event. The following
example should illustrate this a little better:

<!-- SOME HTML CODE -->
<input type="submit" name="dummy" value="whatever" />
<!-- SOME MORE HTML :) -->
If a user clicks the submitbutton and you have registered
the event name dummy for your script, CGI::XMLApplication
will try to call the function eevveenntt__dduummmmyy(()). The script module to handle the dummy event would look something like
the following code:

# Application Module
package myApp;
use CGI::XMLApplication;
@ISA = qw(CGI::XMLApplication);
sub registerEvents { qw( dummy ); } # list of event names
# ...
sub event_dummy {
my ( $self, $context ) = @_;
# your event code goes here
return 0;
}
During the lifecircle of a CGI script, often the implemen
tation starts with ordinary submit buttons, which get
often changed to so called input images, to fit into the
UI of the Website. One does not need to change the code to
make the scripts fit to these changes; CGI::XMLApplication
already did it. The code has not to be changed if the pre
sentation of the form changes. Therefore there is no need
to declare separate events for input images. E.g. an event
called evname makes CGI::XMLApplication tests if evname or
evname.x exist in the querystring.
So a perl artist can implement and test his code without
caring if the design crew have done their job, too ;-)
In many cases an web application is also confronted with
events that can not be represented in with querystring
arguments. For these cases CGI::XMLApplication offers the
possibility to send special events from the eevveenntt__iinniitt(()) function for example in case of application errors. This
is done with the sseennddEEvveenntt(()) Function. This will set a new parameter to the CGI's querystring after removing all
other events. One can only send events that are already registred!.
Although a sendEvent function exists, CGI::XMLApplication
doesn't implement an event queqe. For GUI programmers this
seems like a unnessecary restriction. In terms of CGI it
makes more sense to think of a script as a program, that
is only able to scan its event queqe only once during run
time and stopped before the next event can be thrown. The
only chance to stop the script from handling a certain
event is to send a new event or delete this (or even all)
events from inside the event_init() function. This func tion is always called at first from the run method. If
another event uses the sendEvent function, the call will
have no effect.
method registerEvents
This method is called by the class constructor namely CGI::XMLApplication's nneeww(()) function . Each application should register the events it likes to
handle with this function. It should return an array
of eventnames such as eg. 'remove' or 'store'. This
list is used to find which event a user caused on the
client side.
method run
Being the main routine this should be the only method
called by the script apart from the constructor. All
events are handled inside the method rruunn(()). Since this method is extremly simple and transparent to any
kind of display type, there should be no need to over
ride this function. One can pass a context hash, to
pass external or prefetched information to the appli
cation. This context will be available and acessable
in all events and most extra functions.
This function does all event and serialization related
work. As well there is some validation done as well,
so catched events, that are not implemented, will not
cause any harm.
The Event System
A CGI::XMLApplication is split into two main parts: 1) The
executable script called by the webserver and 2) the
application module which has to be loaded, initialized and
called by the script.
Commonly applications that make use of CGI::XMLApplica
tion, will not bother about the run function too much. All
functionality is kept inside event- and (pseudo-)callback functions. This forces one to implement much more strict code than common perl would allow. What first looks like a
drawback, finally makes the code much easier to under
stand, maintain and finally to extend.
CGI::XMLApplication knows two types of event handlers:
implicit events, common to all applications and explicit
events, reflecting the application logic. The class
assumes that implicit events are implemented in any case.
Those events have reserved names and need not be specified
through registerEvents. Since the class cannot know some thing about the application logic by itself, names of
events have to be explicitly passed to be handled by the
application. As well all event functions have to be imple
mented as member methods of the application class right
now. Because of perls OO interface a class has to be writ
ten inside its own module.
An event may return a integer value. If the event succeeds
(no fatal errors, e.g. database errors) the explicit or
common event function should return a value greater or
eqal than 0. If the value is less than 0, CGI::XMLApplica
tion assumes an application panic, and will not try to
generate a DOM or render it with a stylesheet.
There are 4 defined panic levels:
-1 Stylesheet missing
-2 Stylesheet not available
-3 Event not implemented
-4 Application panic
Apart from Application Panic the panic levels are set internally. An Application Panic should be set if the
application catches an error, that does not allow any
XML/XSLT processing. This can be for example, that a
required perl module is not installed on the system.
To make it clear: If CGI::XMLApplication throws a panic,
the application is broken, not completely implemented or
stylesheets are missing or broken. Application panics are
ment for debugging purposes and to avoid Internal Server Errors. They are not ment as a replacement of a propper error handling!
But how does CGI::XMLApplication know about the correct
event handler?
One needs to register the names of the events the applica
tion handles. This is done by implmenting a regis_
terEvents() function that simply returns an array of event names. Through this function one prepares the CGI::XMLAp
plication to catch the listed names as events from the
query string the client browser sends back to the script.
CGI::XMLApplication tries to call a event handler if a
name of a registred event is found. The coresponding func
tion-name of an event has to have the following format:

event_<eventname>
E.g. event_init handles the init event described below.
Each event has a single Parameter, the context. This is a
hash reference, where the user can store whatever needed.
This context is usefull to pass scriptwide data between
callbacks and event functions around. The callback is even
available and useable if the script does not initialize
the application context as earlier shown in the program
flow chart.
If such a function is not implemented in the application
module, CGI::XMLApplication sets the Event not implemented panic state.
All events have to return an integer that tells about
their execution state as already described.
By default CGI::XMLApplication does not test for other
events if it already found one. The most significant event
is the first name of an event found in the query string all other names are simply ignored. One may change this
behaviour by overriding the tteessttEEvveenntt(()) function.
But still it is a good idea to choose the event names
carefully and do not mix them with ordinary datafield
names.
function testEvent
If it is nesseccary to check which event is relevant
for the current script one can use this function to
find out in event_init(). If this function returns undef, the default event is active, otherwise it
returns the eventname as defined by registerEvents.
In case one needs a special algorithm for event selec
tion one can override this function. If done so, one
can make use of the application context inside this
function since it is passed to tteessttEEvveenntt(()) by the rruunn(()) function.
method sendEvent SCALAR
Sometimes it could be neccessary to send an event by
your own (the script's) initiative. A possible example
could be if you don't have client input but path_info
data, which determinates how the script should behave
or session information is missing, so the client
should not even get the default output.
This can only be done during the event_init() method call. Some coders would prefer the constructor, which
is not a very good idea in this case: While the con
structor is running, the application is not completely
initialized. This can be only ashured in the
event_init function. Therefore all application spe
cific errorhandling and initializing should be done
there.
sendEvent only can be called from event_init, because any CGI::XMLApplication will handle just one event,
plus the init and the exit event. If sendEvent is called from another event than eevveenntt__iinniitt(()) it will take not effect.
It is possible through sendEvent() to keep the script logic clean.
Example:

package myApp;
use CGI::XMLApplication;
@ISA = qw(CGI::XMLApplication);
sub registerEvents { qw( missing ... ) ; }
# event_init is an implicit event
sub event_init {
my ( $self, $context ) = @_;
if ( not ( defined $self->param( $paraname ) &&
length $self->param( $paramname ) ) ){
# the parameter is not correctly filled
$self->sendEvent( 'missing' );
}
else {
... some more initialization ...

}
return 0;
}
... more code ...
# event_missing is an explicit event.
sub event_missing {
my ( $self , $context ) = @_;
... your error handling code goes ...
return -4 if $panic; # just for illustration
return 0;
}
Implicit Events
CGI::XMLApplication knows three implicit events which are
more or less independent to client responses: They are
'init', 'exit', and 'default'. These events already exist
for any CGI::XMLApplication. They need not to be imple
mented separatly if they make no sense for the applica
tion.
event_init
The init event is set before the CGI::XMLApplication
tries to evaluate any of script parameters. Therefore
the event_init method should be used to initialize the
application.
event_exit
The event_exit method is called after all other events
have been processed, but just before the rendering is
done. This should be used, if you need to do something
independend from all events before the data is send to
the user.
event_default
This event is called as a fallback mechanism if
CGI::XMLApplication did not receive a stylesheet id by
an other event handler; for example if no event
matched.
the XML Serialization
The presentation is probably the main part of a CGI
script. By using XML and XSLT this can be done in a stan
dartised manner. From the application view all this can be
isolated in a separate subsystem as well. In CGI::XMLAp
plication this subsystem is implemented inside the sseerriiaall_ iizzee(()) function.
For XML phobic perl programmers it should be cleared, that
CGI::XMLApplication makes real use of XML/XSLT function
alty only inside this function. For all code explained
above it is not required to make use of XML at all.
The XML serialization subsystem of CGI::XMLApplication
tries to hide most of non application specific code from
the application programmer.
This method renders the data stored in the DOM with the
stylesheet returned by the event handler. You should over
ride this function if you like to use a different way of
displaying your data.
If the serialization should be skipped, CGI::XMLApplica
tion will not print any headers. In such case the applica
tion is on its own to pass all the output.
The algorithm used by serialization is simple:
· request the appplication DOM through ggeettDDOOMM(()) · test for XML passthru
· get the stylesheet the application preferes through
sseelleeccttSSttyylleesshheeeett(()) · parse the stylesheet
· transform the DOM with the stylesheet
· set Content-Type and headers
· return the content to the client
If errors occour on a certain stage of serialization, the
application is stopped and the generated error messages
are returned.
CGI::XMLApplication provides four pseudo-callbacks, that
are used to get the application specific information dur
ing serialization. In order of being called by CGI::XMLAp_ plication::serialization() they are:
· getDOM
· setHttpHeader
· getStylesheet
· getXSLTParameter
In fact only getStylesheet has to be implemented. In most
cases it will be a good idea to provide the getDOM func
tion as well. The other functions provider a interface to
make the CGI output more generic. For example one can set
cookies or pass XSL parameters to XML::LibXSLT's xsl pro
cessor.
These methods are used by the serialization function, to
create the content related datastructure. Like event func
tions these functions have to be implemented as class mem
ber, and like event funcitons the functions will have the
context passed as the single parameter.
getDOM()
getDOM() should return the application data as
XML-DOM. CGI::XMLApplication is quite lax if this
function does not return anything - its simply assumed
that an empty DOM should be rendered. In this case a
dummy root element is created to avoid error messages
from XML::LibXSLT.
setHttpHeader()
setHttpHeader should return a hash of headers (but not the Content-Type). This can be used to set the nocache pragma, to set or remove cookies. The keys of the hash
must be the same as the named parameters of CGI.pm's
header method. One does not need to care about the
output of these headers, this is done by CGI::XMLAp
plication automaticly.
The content type of the returned data is usually not
required to be set this way, since the XSLT processor
knows about the content type, too.
getStylesheet()
If the getStylesheet is implemented the CGI::XMLAppli cation will assume the returned value either as a
filename of a stylesheet or as a XML DOM representa
tion of the same. If Stylesheets are stored in a file
accessable from the , one should set the common path
for the stylesheets and let CGI::XMLApplication do the parsing job.
In cases the stylesheet is already present as a string
(e.g. as a result of a database query) one may pass
this string directly to CGI::XMLApplication.
selectStylesheet is an alias for getStylesheet left for compatibility reasons.
If none of these stylesheet selectors succeeds the
Stylesheet missing panic code is thrown. If the pars ing of the stylesheet XML fails Stylesheet not avail_ able is thrown. The latter case will also give some
informations where the stylesheet selection failed.
sseelleeccttSSttyylleesshheeeett(()) has to return a valid path/filename for the stylesheet requested.
getXSLTParameter()
This function allows to pass a set of parameters to
XML::LibXSLT's xsl processor. The function needs only
to return a hash and does not need to encode the
parameters.
The function is the last callback called before the
XSLT processing is done.
Flow Control
Besides the sendEvent() function does CGI::XMLApplication provide to other functions that allow to controll the flow
of the application.
These two functions are related to the XML serialization
and have not affect to the event handling.
passthru()
Originally for debugging purposes CGI::XMLApplication
supports the passthru argument in the CGI query
string. It can be used to directly pass the stringi
fied XML-DOM to the client.
Since there are cases one needs to decide from within
the application if an untransformed XML Document has
to be returned, this function was introduced.
If is called without parameters ppaasssstthhrruu(()) returns the current passthru state of the application. E.g. this
is done inside sseerriiaalliizzaattiioonn(()). Where TRUE (1) means the XML DOM should be passed directly to the client
and FALSE (0) marks that the DOM must get XSL trans
formed first.
Optional the function takes a single parameter, which
shows if the function should be used in set rather
than get mode. The parameter is interpreted as just
described.
If an application sets passthru by itself any external
'passthru' parameter will be lost. This is usefull if
one likes to avoid, someone can fetch the plain
(untransformed) XML Data.
skipSerialization()
To avoid the call of sseerriiaalliizzaattiioonn(()) one should set skipSerialization.

event_default {
my $self = shift;
# avoid serialization call
$self->skipSerialization( 1 ); # use 0 to unset
# now you can directly print to the client, but
don't forget the
# headers.
return 0;
}
Helperfunctions for internal use
function checkPush LIST
This function searches the query string for a parame
ter with the passed name. The implementation is
"imagesave" meaning there is no change in the code
needed, if you switch from input.type=submit to
input.type=image or vv. The algorithm tests wheter a
full name is found in the querystring, if not it tries
tests for the name expanded by a '.x'. In context of
events this function interprets each item part in the
query string list as an event. Because of that, the
algorithm returns only the first item matched.
If you use the event interface on this function, make
sure, the HTML-forms pass unique events to the script.
This is neccessary to avoid confusing behaviour.
This function is used by testEvent() so if it is required to change the way CGI::XMLApplication selects
events, override that function.
method panic SCALAR
This a simple error message handler. By default this
function will print some information to the client
where the application failed. While development this
is a useful feature on production system this may pass
vunerable informations about the system to the out
side. To change the default behaviour, one may write
his own panic method or simply set $CGI::XMLApplica_ tion::Quiet to 1. The latter still causes the error page but does not send any error message.
The current implementation send the 404 status to the
client if any low level errors occour ( e.g. panic
levels > -4 aka Application Panic). Commonly this
really shows a "Not Found" on the application Level.
Application Panics will set the 500 error state. This
makes this implementation work perfect with a mod_perl
installation.
In case mod_perl is used to handle the script one
likes to set CGI::XMLApplication::Quiet to 2 which will cause CGI::XMLApplication just to return the
error state while mod_perl does the rest.
method setPanicMsg $SCALAR
This useful method, helps to pass more specific error
messages to the user. Currently this method is not
very sophisticated: if the method is called twice,
only the last string will be displayed.
function getPanicMsg
This method returns the panic message set by setPan_
icMsg().
CGI Extras
The following functions are some neat features missing in
CGI.pm
function checkFields LIST
This is an easy way to test wether all required fields
are filled out correctly. Called in array context the
function returns the list of missing parameter. (Dif
ferent to param() which returns all parameter names). In scalar context the function returns a boolean
value.
function getParamHash LIST
This function is a bit better for general data pro
cessing as the standard CGI::Vars function. While Vars
sets a keys for each parameter found in the query
string, getFieldsAsHash returns only the requested
fields (as long they aren't NULL). This is useful in
scripts where the script itself handles different kind
of data within the same event.
Since the function relies on Vars the returned data
has the same structure Vars returns.
some extra functions for stylesheet handling
The getStylesheet() function should return either a file name or a stringnyfied XSL-DOM. For the firstcase it can
be a restriction to return the fully qualified path. The
following functions allow to set the stylesheetpath sys
temwide.
method setStylesheetDir DIRNAME
alias for setStylesheetPath
method setStylesheetPath DIRNAME
This method is for telling the application where the
stylesheets can be found. If you keep your stylesheets
in the same directory as your script -- IMHO a bad
idea -- you might leave this untouched.
function getStylesheetPath
This function is only relevant if you write your own
sseerriiaalliizzaattiioonn(()) method. It returns the current path to the application stylesheets.

SEE ALSO

CGI, perlobj, perlmod, XML::LibXML, XML::LibXSLT

AUTHOR

Christian Glahn, christian.glahn@uibk.ac.at

VERSION

1.1.1
Copyright © 2010-2025 Platon Technologies, s.r.o.           Home | Man pages | tLDP | Documents | Utilities | About
Design by styleshout