Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 4e5f14d1da
Fetching contributors…

Cannot retrieve contributors at this time

159 lines (106 sloc) 3.38 kb
package Plack::Middleware::XSLT;
use strict;
# ABSTRACT: XSLT transformations with Plack
use parent 'Plack::Middleware';
use HTTP::Exception;
use Plack::Response;
use Plack::Util::Accessor qw(cache path parser_options);
use Try::Tiny;
use XML::LibXML 1.62;
use XML::LibXSLT 1.62;
my ($parser, $xslt);
sub call {
my ($self, $env) = @_;
my $r = $self->app->($env);
my $style = $env->{''};
return $r if !defined($style) || $style eq '';
my $path = $self->path;
$style = "$path/$style" if defined($path);
my ($status, $headers, $body) = @$r;
my $doc = $self->_parse_body($body);
my ($output, $media_type, $encoding) = $self->_xform($style, $doc);
my $res = Plack::Response->new($status, $headers, $output);
$res->content_type("$media_type; charset=$encoding");
return $res->finalize();
sub _xform {
my ($self, $style, $doc) = @_;
if (!$xslt) {
if ($self->cache) {
require XML::LibXSLT::Cache;
$xslt = XML::LibXSLT::Cache->new;
else {
$xslt = XML::LibXSLT->new;
my $stylesheet = $xslt->parse_stylesheet_file($style);
my $result = try {
$stylesheet->transform($doc) or die("XSLT transform failed: $!");
catch {
for my $line (split(/\n/, $_)) {
HTTP::Exception->throw($1) if $line =~ /^(\d\d\d)(?:\s|\z)/;
my $output = $stylesheet->output_as_bytes($result);
my $media_type = $stylesheet->media_type();
my $encoding = $stylesheet->output_encoding();
return ($output, $media_type, $encoding);
sub _parse_body {
my ($self, $body) = @_;
if (!$parser) {
my $options = $self->parser_options;
$parser = $options
? XML::LibXML->new($options)
: XML::LibXML->new;
my $doc;
if (ref($body) eq 'ARRAY') {
my $xml = join('', @$body);
$doc = $parser->parse_string($xml);
else {
$doc = $parser->parse_fh($body);
return $doc;
sub _cache_hits {
my $self = shift;
return $xslt->cache_hits
if $xslt && $xslt->isa('XML::LibXSLT::Cache');
return 0;
# in your .psgi
enable 'XSLT';
# in your app
$env->{''} = 'stylesheet.xsl';
return [ 200, $headers, [ $xml ] ];
Plack::Middleware::XSLT converts XML response bodies to HTML, XML, or text
using XML::LibXSLT. The XSLT stylesheet is specified by the environment
variable ''. If this variable is undefined or empty, the response
is not altered. This rather crude mechanism might be enhanced in the future.
The Content-Type header is set according to xsl:output. Content-Length is
=over 4
=item cache
enable 'XSLT', cache => 1;
Enables caching of XSLT stylesheets. Defaults to false.
=item path
enable 'XSLT', path => 'path/to/xsl/files';
Sets a path that will be prepended if contains a relative path.
Defaults to the current directory.
=item parser_options
enable 'XSLT', parser_options => \%options;
Options that will be passed to the XML parser when parsing the input
document. See L<XML::LibXML::Parser/"PARSER OPTIONS">.
Jump to Line
Something went wrong with that request. Please try again.