NAME
Apache::AxKit::Language::XSP::ObjectTaglib - Helper for OO Taglibs
SYNOPSIS
package MyTaglib;
use Apache::AxKit::Language::XSP::ObjectTaglib;
@ISA = qw(Apache::AxKit::Language::XSP::ObjectTaglib);
@specification = (
...
);
DESCRIPTION
This is an AxKit tag library helper for easily wrapping object-oriented classes into XSP tags. The interface to the class is through a specification which your taglib provides as a package variable. You may wrap single or multiple classes within the same taglib, iterate over several objects, and call methods on a given object.
Here is a sample specification:
@specification = (
{ tag => "name", context => "resources", target => "resource" },
{ tag => "courses", type => "special",
start => \&start_courses, end => \&end_courses },
{ tag => "name", target => "course" },
{ tag => "code", target => "course" },
{ tag => "presentations",
target => "course", type => "loop", iterator => "presentation" },
{ tag => "prerequisites",
target => "course", type => "loop", iterator => "course" },
{ tag => "description", target => "course", type => "as_xml" },
{ tag => "summary", target => "course", type => "as_xml" },
...
{ tag => "size", target => "presentation", notnull => 1 },
);
Here's what this means:
{ tag => "name", context => "resources", target => "resource" },
Define a tag called name
which occurs inside of another tag called resources
. (We'll define a top-level name
tag later, so this context-sensitive override has to come first.) When this tag is seen, the method name
will be called on the variable $_xsp_axkit_xsp_coursebooking_resource
. (This example is taken from the AxKit::XSP::CourseBooking
taglib, and so all variable names used by the example taglib start with _xsp_axkit_xsp_coursebooking_
.)
{ tag => "courses", type => "special",
start => \&start_courses, end => \&end_courses },
courses
will be the main entry point for our tag library, and as such needs to do some special things to set itself up. Hence, it uses a special
type, and provides its own handlers to handle the start and end tag events. These handlers will be responsible for setting up $_xsp_axkit_xsp_coursebooking_course
, used in the following tags, and looping over the possible courses, setting $_xsp_axkit_xsp_coursebooking_course
appropriately.
{ tag => "name", target => "course" },
{ tag => "code", target => "course" },
When we see the name
tag, we call the name
method on $_xsp_axkit_xsp_coursebooking_course
. Similarly, the code
tag calls the code
method on the same object.
{ tag => "presentations",
target => "course", type => "loop", iterator => "presentation" },
Each course object has a presentations
method, which is wrapped by the presentations
tag. This methods returns a list of objects representing the presentations of a course; the presentations
tag sets up a loop, with $_xsp_axkit_xsp_coursebooking_presentation
as the iterator. Hence, inside of a presentations
tag, target => "presentation"
will cause the method to be called on each presentation object in turn.
{ tag => "prerequisites",
target => "course", type => "loop", iterator => "course" },
This is slightly dirty. We want a prerequisites
tag to refer to other course objects, namely, the courses which are required for admission to the current course. ie:
<c:courses code="foo">
For course <c:name/>, you need to take the following courses:
<c:prerequisites>
<li> <c:name/>
</c:prerequisites>
</c:courses>
So when we see the prerequisites
tag, we call the prerequisites
method on our course
target, $_xsp_axkit_xsp_coursebooking_course
. This returns a list of new course objects, which we loop over. (type =
"loop">)
Our loop iterator will be $_xsp_axkit_xsp_coursebooking_course
itself, so the other tags will work properly on the iterated courses.
Some code is worth a thousand words. The generated Perl will look something like this:
for my $_xsp_axkit_xsp_coursebooking_course
($_xsp_axkit_xsp_coursebooking_course->prerequisites) {
... $_xsp_axkit_xsp_coursebooking_course->name ...
}
Back to our specification:
{ tag => "description", target => "course", type => "as_xml" },
{ tag => "summary", target => "course", type => "as_xml" },
These tags call the description
and summary
methods on the course object, this time making sure that the result is valid XML instead of plain text. (This is because we store the description in the database as XML, and don't want it escaped before AxKit throws it onto the page.)
{ tag => "size", target => "presentation", notnull => 1 },
When we see size
, we call the size
method on $_xsp_axkit_xsp_coursebooking_presentation
, the presentation object we set up in a loop above. We ensure that we get some output back from this method.
Here's another quick example:
our @specification = (
{ tag => "person", type => "special",
start => \&start_person, end => \&end_person },
{ tag => "name", key => "cn", target => 'person'},
...
);
This comes from a wrapper around LDAP. As before, the person
tag at the top level has two subroutines to set up the person
target. (which in this case will be $_xsp_axkit_xsp_ldap_person
) When a name
tag is seen inside of the person
tag, a method is called on that target. This time, we use key
to say that the method name is actually cn
, rather than name
. Hence the following XSP:
<b:person dn="foo">
<b:name/>
</b:person>
generates something like this:
{
my $_xsp_axkit_xsp_ldap_person = somehow_get_ldap_object(dn => "foo");
...
$_xsp_axkit_xsp_ldap_person->cn();
...
}
All clear?
LICENSE
GPL/AL.
AUTHOR
Simon Cozens, simon@ermine.ox.ac.uk
.