NAME

Role::LibXSLT::Extender

VERSION

version 1.140260

SYNOPSIS

# your extension class
package My::Special::XSLTProcessor
use Moose;
with 'MooseX::LibXSLT::Extender';

sub set_extension_namespace {
    return 'http:/fake.tld/my/app/namespace/v1'
}

sub special_text_munger {
    my $self = shift;
    my $text = shift;

    # magic happens here

    return $text;
}

-------------------
# in your XSLT stylesheet

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:myapp="http:/fake.tld/my/app/namespace/v1">

<xsl:template match="/some/xpath">
    <!-- pass the current text node to special_text_munger()
         in your extension class. -->
    <foo><xsl:value-of select="myapp:special_text_munger(.)"/></foo>
</xsl:template>

-------------------
# in your application or script

my $extended = My::Special::XSLTProcessor->new();

# load the XML and XSLT files
my $style_dom = XML::LibXML->load_xml( location=> $xsl_file );
my $input_dom = XML::LibXML->load_xml( location=> $xml_file );
my $stylesheet = $extended->parse_stylesheet($style_dom);

# your custom extensions are called here
my $transformed_dom = $stylesheet->transform( $input_dom );

# dump the result to STDOUT
print $stylesheet->output_as_bytes($transformed_dom);

DESCRIPTION

Simple Moose Role that instantiates an XML::LibXSLT processor and registers a series of site-specific Perl extension functions that can be called from within your XSLT stylesheets.

WHY WOULD I WANT THIS?

XSLT is great for recursively transforming nested XML documents but operating on the text in those documents can be time consuming and error-prone. Perl is great for all sort of things, but transforming nested XML documents programmatically is the source of much unnecessary pain and consternation. This module seeks to bridge the gap by letting you use XSLT for what it is best at while using the power of Perl for everything else.

METHODS

set_extension_namespace

In addition to the various custom functions in your extention class, you are required to implement the set_extension_namespace() method. This namespace URI will be used to register your functions with the LibXSLT processor and is the mechanism by which your custom functions will be available from within your XSLT stylesheets.

For example, if your extention class has the following:

sub set_extension_namespace { return 'http:/fake.tld/my/app/namespace/v1'; }

You can access functions in this namespace by declaring that namespace in your XSLT stylesheet:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:myapp="http:/fake.tld/my/app/namespace/v1"
>

And then using the bound prefix to call the functions in that namespace:

<xsl:value-of select="myapp:some_function_name( arguments )" />
xslt_processor

This method returns the instance of the XML::LibXSLT processor with your extension functions registered and ready to go.

FUNCTIONS ARE METHODS, NOT SIMPLE SUBROUTINES

Note that this Role gives your extension functions extra magical powers beyond the mechanism provided by XML::LibXSLT by making your functions into methods rather than simple subroutines. From the example above:

sub special_text_munger {
    my $self = shift;
    my $text = shift;

    # magic happens here

    return $text;
}

Note that the first argument passed to this function is the instance of this class, and the text node (or nodelist) sent over from the XML document is the second argument. This gives your functions access to all other attributes, methods, etc. contained in this class without having to resort to global variables and so forth. This gives your functions (and the stylesheets that use them) the power to easily alter the document by adding nodes based on database queries, perform complex operations on data using other objects, and a myriad of other options.

KEEPING PRIVATE THINGS PRIVATE

This Role uses Moose's handy introspection facilities to avoid registering methods that you probably don't want to make available to your stylesheets (attribute accessors, builders, etc.) but it has no way of differentiating between methods that you want to register and those that you will use for other purposes. To that end, if you want to implement methods that will not be registered, simply use the "make this private" convention and prepend the method's name with an underscore:

sub my_function { # i'll be registered and available in the stylesheets. }

sub _my_function { # But I won't be. }