Converting different formats: Providers and Recipes |
Not only on the Embperl website the content has different source formats.
For example the documentation is written in POD (Plain Old Documentation)
while the home page is HTML and other pages are HTML with some Perl code
in it. To manage these different formats you can give the syntax
parameter to the Execute function and tell Embperl how the source should
be interpreted. Embperl comes with different predefined syntaxes
(among others SSSI, ASP, Text, Perl, RTF, POD), but you can also
define your own syntax. In the above example we can see that when reading the configuration file,
syntax => 'Perl' is used to tell Embperl that the configuration file
contains only Perl code. Similar you can use syntax => 'Text' to pass
the file through without doing any interpretation of the content. Things get more compilcated when we try to process POD, because Embperl
not only has to understand the syntax, but also need to generate
the markup (HTML in this case). For this purpose Embperl provides recipes. A recipe defines which steps
are taken to process a source file. Each of these steps are done by a provider.
If no recipe is selected, the default is used which defines the steps
parse, compile, execute and output. Additionally there are recipes
for processing XML and doing XSLT as part of the Embperl distribution.
If they don't fit your needs, you can define your own recipes.
For displaying POD on the Embperl website, we use the EmbperlXSLT
recipe. Addtionaly we set the syntax parameter to POD. This
tells Embperl to convert the POD source into XML data, so the
XSLT provider defined by the recipe can transform this into
the destination format (e.g. HTML). To make this happen
an additional provider cares about reading the XSL stylesheet
and providers transforms the text version
of the XML and XSL into some internal format suitable for the
XSLT processor. Since Embperl is able to cache any of these
intermediate results, this can speed up pocessing considerably,
when doing a lot of pages. Since we don't want to configure for any individual page which recipe
to use, it seems to be a good idea to use file extentions
for selecting a recipe. This can be implemented by overiding the method get_recipe
in the application object. Embperl is calling this
method before every file is processed. So in our
epwebapp.pl we define the following method: sub get_recipe
{
my ($class, $r, $recipe) = @_ ;
my $self ;
my $param = $r -> component -> param ;
my $config = $r -> component -> config ;
my ($src) = $param -> inputfile =~ /^.*\.(.*?)$/ ;
my ($dest) = $r -> param -> uri =~ /^.*\.(.*?)$/ ;
if ($src eq 'pl')
{
$config -> syntax('Perl') ;
return Embperl::Recipe::Embperl -> get_recipe ($r, $recipe) ;
}
if ($src eq 'pod' || $src eq 'pm')
{
$config -> escmode(0) ;
if ($dest eq 'pod')
{
$config -> syntax('Text') ;
return Embperl::Recipe::Embperl -> get_recipe ($r, $recipe) ;
}
$config -> syntax('POD') ;
if ($dest eq 'xml')
{
return Embperl::Recipe::Embperl -> get_recipe ($r, $recipe) ;
}
$config -> xsltstylesheet('pod.xsl') ;
$r -> param -> uri =~ /^.*\/(.*)\.(.*?)$/ ;
$param -> xsltparam({
page => $fdat{page} || 0,
basename => "'$1'",
extension => "'$2'",
imageuri => "'$r->{imageuri}'",
baseuri => "'$r->{baseuri}'",
}) ;
return Embperl::Recipe::EmbperlXSLT -> get_recipe ($r, $recipe) ;
}
if ($src eq 'epd')
{
$config -> escmode(0) ;
$config -> options($config -> options | &Embperl::Constant::optKeepSpaces) ;
if ($dest eq 'pod')
{
$config -> syntax('EmbperlBlocks') ;
return Embperl::Recipe::Embperl -> get_recipe ($r, $recipe) ;
} $config -> xsltstylesheet('pod.xsl') ;
$r -> param -> uri =~ /^.*\/(.*)\.(.*?)$/ ;
$param -> xsltparam({
page => $fdat{page} || 0,
basename => "'$1'",
extension => "'$2'",
imageuri => "'$r->{imageuri}'",
baseuri => "'$r->{baseuri}'",
}) ;
return Embperl::Recipe::EmbperlPODXSLT -> get_recipe ($r, $recipe) ;
}
if ($src eq 'epl' || $src eq 'htm')
{
$config -> syntax('Embperl') ;
return Embperl::Recipe::Embperl -> get_recipe ($r, $recipe) ;
}
$config -> syntax('Text') ;
return Embperl::Recipe::Embperl -> get_recipe ($r, $recipe) ;
} First get_recipe determinates the extentions of the
source and destination file ($src and $dest ).
Depending on the combination of these two it selects
the correct recipe. Because of that you can produce
different output formats (e.g. POD, XML, HTML) from the
same source. Additional get_recipe set some parameters
like syntax, output escaping and parameters
passed to the XSLT stylesheet, so they fit to the desired
source and destination formats.
|