8.4 Custom Language Modules


AxKit Language modules provide various ways to transform XML content during delivery. For example, Apache::AxKit::Language::XSP provides AxKit's eXtensible Server Pages implementation, while Apache::AxKit::Language::LibXSLT is one of two Language modules that offers the ability to transform content using XSLT stylesheets. Usually, a Language module is simply a wrapper around the implementation of proven or promising XML transformation technology that allows AxKit to pass data to that processor and capture the result for delivery or further processing.

New Language modules are added to AxKit at runtime using the AxAddStyleMap directive. This directive requires two arguments: the MIME type used to associate transformations with the given Language processor and the Perl package name of the module that implements that processor:

 # Add the Language module AxAddStyleMap application/x-mylang Language::MyCustomLanguage # Then, later, an AddProcessor directive that uses your new Language to apply # the 'default.mlg' stylesheet AxAddProcessor application/x-mylang /styles/default.mlg 

8.4.1 Language API

The Language module interface consists of a single handler method expected to encapsulate the entire transformation process. This method is passed, in order: the current Apache object, a reference to the ContentProvider that will pull (or has pulled) in the original XML source, a reference to the StyleProvider that the Language module can use to get sources for any stylesheet to be applied, and a Boolean flag that indicates whether the current Language processor is the last entry in the processing pipeline.

Access to the source content (the data being transformed) varies based on two factors: whether the current Language processor is first in the processing chain, and, if not, whether the previous Language processor stored its result as a string or as an XML::LibXML::Document instance. If the given Language processor is first in the pipeline, it must call one of the ContentProvider instance's accessors methods , get_fh( ) , get_strref( ) , or get_dom( ) to fetch the content to transformthe method used should be based on which is the most efficient for the processor associated with the Language module to consume . If the current Language module is not the first processor in the chain, the content was stored by the preceding processor in the Apache instance's pnotes table, either in the xml_string or dom_tree fields, depending on what the previous Language module returned. It sounds a little messy and convoluted, but this approach provides Language modules that are implemented on top of XML::LibXML with an easy way to accept and return preprocessed document instances (avoiding the overhead of serializing the objects to a string and reparsing them at each stage), while still allowing those modules based on other XML libraries to simply consume the content as a string.

 sub handler {     my ($r, $content_provider, $style_provider, $last_in_chain ) = @_;          # Your processor wants its XML as a string          my $content;          # Always check for previous processing, first     if (my $string = $r->pnotes('xml_string') ) {         $content = $string;         delete $r->pnotes('xml_string');     }     elsif ( my $dom = $r->pnotes('dom_tree') ) {         $content = $dom->toString;         delete $r->pnotes('dom_tree');     }     # If you make it this far, you are the first in the processing chain     # and need to use the ContentProvider     else {         $content = $content_provider->get_strref;     }          my $output          # The real processing happens here, ending with      # $output containing the result of the transformation.          $r->pnotes('xml_string', $output );     return Apache::Constants::OK; } 

What to do with the result of the Language module's transformation also varies. Language modules whose result is returned as a string containing a well- formed XML document should store that result in the xml_string field in the Apache object's pnotes table. If the result is an XML::LibXML::Document instance, it may be stored in the pnotes dom_tree field instead. Modules that store their results in pnotes in this way are most generic, since they can appear at any stage in the processing pipeline.

However, some Language modules should not use pnotes to store their results because of the type of content generated during the transformation process. For example, the AxPoint Language module that ships with AxKit generates PDF slideshows from XML contenta result that would choke any downstream processors expecting to consume a well-formed XML document. In cases in which the result of the transformation cannot be an XML document (or XML::LibXML::Document instance), the Language module is expected to use the Apache object to send the result directly to the requesting client. While doing so limits these modules to the last position in the processing chain, it means that practically any format can be generated (PDF document, binary image, RTF text, etc.). Whether the content is stored in pnotes for further processing or sent directly to the client, the handler method should always return OK from the Apache::Constants class to let AxKit know that the process completed successfully

 sub handler {     my ($r, $content_provider, $style_provider, $last_in_chain ) = @_;          unless ( $last_in_chain ) {         throw Apache::AxKit::Exception::Error(            -text => _ _PACKAGE_ _ . " is not a generic Language module and may only  appear as the last processor in the chain."           );     }          my $result;          # The transformation happens here, storing a binary     # or other non-XML result in $result.          # You are the last in the chain, so you can     # send the data directly to the client using the Apache object.     $r->print( $result );          return Apache::Constants::OK; } 

As an example of an AxKit Language module, let's create an interface to Petr Cimprich's Perl implementation of STX (Streaming Transformations for XML), XML::STX. The code in Example 8-3 reflects an early beta implementation of STX. The AxKit interface used for the final implementation is likely to be quite different.

Example 8-3. Language::STX
 package Language::STX; use strict; use vars qw( @ISA ); use XML::STX; use XML::SAX::ParserFactory; use Apache::AxKit::Language; use XML::SAX::Writer; @ISA = qw( Apache::AxKit::Language ); sub handler {     my $class = shift;     my ($r, $xml, $style, $last_in_chain) = @_;     my ($xmlstring, $xml_doc);     if (my $dom = $r->pnotes('dom_tree')) {         $xml_doc = $dom;     }     else {         $xmlstring = $r->pnotes('xml_string');         delete $r->pnotes( )->{'xml_string'};     }     my $stx_style = undef;     # get the source for the STX stylesheet from the StyleProvider and parse     # it to get the compiled XSLT processor.     my $stx_compiler = XML::STX::Compiler->new( );     my $parser = XML::SAX::ParserFactory->parser( Handler => $stx_compiler );     my $style_stringref = $style->get_strref( );     eval {         $stx_style = $parser->parse_string( $$style_stringref );     };     if ( my $error = $@ ) {         throw Apache::AxKit::Exception::Error( -text => "Error parsing  STX stylesheet: $error ." );     }     my $result = '';     my $error;     my $output_handler = XML::SAX::Writer->new( Output => $result );     my $stx_handler = XML::STX->new( Handler => $output_handler, Sheet => $stx_style );     if ( $xml_doc ) {         eval {             require XML::LibXML::SAX::Parser;             my $p = XML::LibXML::SAX::Parser->new( Handler => $stx_handler );             $p->generate( $xml_doc );         };     }     else {         my $p = XML::SAX::ParserFactory->parser( Handler => $stx_handler );         if ($xmlstring) {             eval {                 $p->parse_string( $xmlstring );             };             $error = $@ if $@;         }         else {             $xmlstring = ${$xml->get_strref( )};             eval {                 $p->parse_string( $xmlstring );             };             $error = $@ if $@;         }     }     if ( length( $error ) ) {         throw Apache::AxKit::Exception::Error(                     -text => "STX Processing Error: $error"                     );     }     delete $r->pnotes( )->{'dom_tree'};     $r->pnotes('xml_string', $result);     return Apache::Constants::OK; } 1; 

XML Publishing with AxKit
XML Publishing with Axkit
ISBN: 0596002165
EAN: 2147483647
Year: 2003
Pages: 109
Authors: Kip Hampton

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net