Apache-XPP
view release on metacpan or search on metacpan
man/xpptagtut.pod view on Meta::CPAN
Apache::XPP is a great tool for embedding Perl in your web pages, partly
because it allows you to extend it's built-in tag parser with custom XPP tags
of your own. If the built-in tags don't meet all of your needs, you can create
new tags by subclassing Apache::XPP and Apache::XPP::PreParse.
=head1 CREATING CUSTOM TAGS
There are two types of tags in XPP, just as there are in HTML. In XPP, they're
called single tags and double tags. Single tags consist of one element, and do
not have an end tag. Double tags consist of both a starting and ending element,
with content inbetween. Note that there is no way to create a tag with an
"optional" ending element (like E<lt>PE<gt> in HTML).
XPP tags can accept any number of C<option="value">-style options, but they
cannot accept single word options.
For this tutorial, we're going to create two custom tags, one of each type.
The E<lt>SHIFTE<gt> tag is a single tag, it is used to shift an element off
of an array. The E<lt>REPLACEE<gt> tag is a double tag, it displays the text
appearing between it's starting and ending elements, replacing a given pattern
with a specified string.
We'll call our subclasses My::XPP and My::XPP::PreParse.
=head2 Subclassing Apache::XPP
Only one method in this class needs to be overridden, which is the one that
XPP uses to determine what PreParse class to use. This method is called
C<preparseclass>, and it returns the name of the PreParse class you
are going to implement (we'll get to that).
Here's the complete Apache::XPP subclass:
package My::XPP;
use strict;
use Apache::XPP;
use vars qw( @ISA );
@ISA = qw( Apache::XPP );
sub preparseclass {
return "My::XPP::PreParse";
}
1;
That's it. All the functionality of this class is still handled by
Apache::XPP, you've instructed it to use a different PreParse class.
Of course, creating that PreParse class is a little more complicated.
=head2 Subclassing Apache::XPP::PreParse
Subclassing Apache::XPP::PreParse to create a custom tags involves two
basic steps. The first thing you have to do it create a class variable
called C<@parsers> that contains the names of all the parser methods you're
creating to handle your custom tags. Each tag will have exactly one parser
method associated with it. The second step is to implement those parser methods
for your custom tags.
The beginning of our Apache::XPP::PreParse subclass looks like this:
package My::XPP::PreParse;
use strict;
use Apache::XPP::PreParse;
use vars qw( @ISA @parsers );
@ISA = qw( Apache::XPP::PreParse );
@parsers = (
@Apache::XPP::PreParse::parsers,
qw( parser_xppshift parser_xppreplace )
);
Once we get the usual formalities of package declaration and inheritance out
of the way, we create the C<@parsers> array by filling it with the contents
of the parent class's parsers array, then adding our own custom parsers.
In this example, we've added two names to the list. These are the names of the
custom parser methods we're going to implement. Now we need to write the code
for these methods.
=head2 Implementing a single tag parser
Our single tag is called E<lt>SHIFTE<gt>, it has the following form:
<SHIFT as="$scalarname" array="@arrayname">
In the above example, the first element is shifted off of C<@arrayname> and
assigned to the lexically-scoped variable C<$scalarname>. The C<array> option
can be omitted, in which case @_ is used.
Your parser method should accept two arguments. The first is the PreParse
object itself, the second is the text you're parsing. To implement a single
tag parser, you need to pass this text along to an XPP::PreParse method
called C<stag> (as in I<s>ingle I<tag>), along with some other data. Your
parser is called as an object method, and calls to C<stag> are made on that
object.
Here's the beginning of our parser method for E<lt>SHIFTE<gt>:
sub parser_shift {
my $self = shift;
my $text = shift;
$self->stag( $text,
Simple enough, but we need to pass some more information to C<stag>. First,
we need to specify what text our tag starts with, including the opening angle
bracket. This one is fairly simple:
'<SHIFT',
The last argument is a single arrayref, which in turn contains at least one
nested arrayref. Think of each nested arrayref as a sort of case statment.
Every nested arrayref will contain 3 values, except for the last one
(the default case), which will contain only two.
For the non-default cases, the first value is the name of an option that
must be present for that case to be used. The next value is a C<printf>-style
format string with a number of string placeholders (C<%s>). This string should
( run in 1.859 second using v1.01-cache-2.11-cpan-b16cb0d3907 )