Embperl - building dynamic websites with Perl


Converting different formats: Providers and Recipes
[ << Prev: Defining the navigation structure ] [ Content ] [ Next: Internationalisation >> ]

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.


[ << Prev: Defining the navigation structure ] [ Content ] [ Next: Internationalisation >> ]


© 1997-2023 Gerald Richter / actevy