File Coverage

lib/Any/Renderer/XSLT.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             package Any::Renderer::XSLT;
2              
3             # $Id: XSLT.pm,v 1.14 2006/09/04 12:15:53 johna Exp $
4              
5 1     1   5 use strict;
  1         2  
  1         31  
6 1     1   477 use Cache::AgainstFile;
  0            
  0            
7             use XML::LibXSLT;
8             use XML::LibXML;
9             use Any::Renderer::XML;
10              
11             # a global XML parser and cache
12             use vars qw($VERSION $XMLParser $Cache $CacheMaxItems $CacheMaxAtime $CachePurgeInterval $CacheLastPurged);
13              
14             #Package-level cache and settings
15             $Cache = undef; #Generated on first use
16             $CacheMaxItems = 1000;
17             $CacheMaxAtime = 6 * 60 * 60; # seconds (6 hours)
18             $CachePurgeInterval = 60 * 60 ; # seconds (1 hour)
19             $CacheLastPurged = undef;
20              
21             $VERSION = sprintf"%d.%03d", q$Revision: 1.14 $ =~ /: (\d+)\.(\d+)/;
22              
23             use constant FORMAT_NAME => "XSLT";
24              
25             sub new
26             {
27             my ( $class, $format, $options ) = @_;
28             die("Invalid format $format") unless($format eq FORMAT_NAME);
29              
30             $Cache ||= _init_cache ();
31              
32             my $self = {
33             'template_file' => $options->{'Template'} || $options->{'TemplateFilename'},
34             'template_string' => $options->{'TemplateString'},
35             'options' => $options || {},
36             'xml_renderer' => new Any::Renderer::XML('XML',$options),
37             'cache' => $options->{'NoCache'}? undef: $Cache,
38             };
39              
40             die("You must specify either a template filename or string containing a template") unless($self->{template_file} || defined $self->{template_string});
41             bless $self, $class;
42              
43             return $self;
44             }
45              
46             sub render
47             {
48             my ( $self, $data ) = @_;
49              
50             TRACE ( "Rendering XSLT" );
51             DUMP ( $data );
52              
53             my $stylesheet = '';
54             my $template_file = $self->{template_file};
55             my $template_string = $self->{template_string};
56             if ( $template_file )
57             {
58             if( $self->{cache} )
59             {
60             TRACE ( "Fetching XSLT from cache" );
61             $stylesheet = $self->{cache}->get( $template_file );
62             _purge_cache($self->{cache}) if(time - $CacheLastPurged > $CachePurgeInterval);
63             }
64             else
65             {
66             TRACE ( "Compiling XSLT from filesystem" );
67             $stylesheet = _xslt_from_file ( $template_file );
68             }
69             }
70             elsif ( $template_string )
71             {
72             TRACE ( "Compiling XSLT from string" );
73             $stylesheet = _xslt_from_string($template_string);
74             }
75             else
76             {
77             die ( "No template provided!" );
78             }
79              
80             my $xml = $self->{xml_renderer}->render($data);
81             my $transformed = $stylesheet->transform($XMLParser->parse_string ( $xml ) );
82             return $stylesheet->output_string ( $transformed );
83             }
84              
85             sub requires_template
86             {
87             return 1;
88             }
89              
90             sub available_formats
91             {
92             return [ FORMAT_NAME ];
93             }
94              
95             #
96             # Cache management
97             #
98              
99             sub _init_cache
100             {
101             $CacheLastPurged = time();
102             return new Cache::AgainstFile ( \&_xslt_from_file, {
103             'Method' => 'Memory',
104             'Grace' => 0, # seconds
105             'MaxATime' => $CacheMaxAtime,
106             'MaxItems' => $CacheMaxItems,
107             } );
108             }
109              
110             sub _purge_cache
111             {
112             my $cache = shift;
113             return unless defined $cache;
114             $cache->purge();
115             $CacheLastPurged = time();
116             }
117              
118             sub _xslt_from_file
119             {
120             my ( $filename ) = @_;
121             TRACE ( "Any::Renderer::XSLT::_xslt_from_file - reading XSLT from disk '$filename'" );
122              
123             $XMLParser ||= new XML::LibXML ();
124              
125             my $xslt = new XML::LibXSLT ();
126             my $stylesheet = $xslt->parse_stylesheet($XMLParser->parse_file ( $filename ));
127             return $stylesheet;
128             }
129              
130             sub _xslt_from_string
131             {
132             my ( $string ) = @_;
133             TRACE ( "Any::Renderer::XSLT::_xslt_from_string" );
134              
135             $XMLParser ||= new XML::LibXML ();
136              
137             my $xslt = new XML::LibXSLT ();
138             my $stylesheet = $xslt->parse_stylesheet($XMLParser->parse_string( $string ));
139             return $stylesheet;
140             }
141              
142             sub TRACE {}
143             sub DUMP {}
144              
145             1;
146              
147             =head1 NAME
148              
149             Any::Renderer::XSLT - render by XLST of XML element representation of data structure
150              
151             =head1 SYNOPSIS
152              
153             use Any::Renderer;
154              
155             my %xml_options = ();
156             my %options = (
157             'XmlOptions' => \%xml_options,
158             'Template' => 'path/to/template.xslt',
159             );
160             my $format = "XSLT";
161             my $r = new Any::Renderer ( $format, \%options );
162              
163             my $data_structure = [...]; # arbitrary structure code
164             my $string = $r->render ( $data_structure );
165              
166             You can get a list of all formats that this module handles using the following syntax:
167              
168             my $list_ref = Any::Renderer::XSLT::available_formats ();
169              
170             Also, determine whether or not a format requires a template with requires_template:
171              
172             my $bool = Any::Renderer::XSLT::requires_template ( $format );
173              
174             =head1 DESCRIPTION
175              
176             Any::Renderer::XSLT renders a Perl data structure as an interstitial XML
177             representation (via Any::Renderer::XML) and then proceeds to apply a XSLT transformation to it to generate
178             the final output.
179              
180             XSL Templates expressed as filenames are cached using a package-level in-memory cache with Cache::AgainstFile.
181             This will stat the file to validate the cache before using the cached object, so if the template is updated,
182             this will be immediately picked up by all processes holding a cached copy.
183              
184             =head1 FORMATS
185              
186             =over 4
187              
188             =item XSLT
189              
190             =back
191              
192             =head1 METHODS
193              
194             =over 4
195              
196             =item $r = new Any::Renderer::XSLT($format,\%options)
197              
198             C<$format> must be C.
199             See L for a description of valid C<%options>.
200              
201             =item $scalar = $r->render($data_structure)
202              
203             The main method.
204              
205             =item $bool = Any::Renderer::XSLT::requires_template($format)
206              
207             True in this case.
208              
209             =item $list_ref = Any::Renderer::XSLT::available_formats()
210              
211             Just the one - C.
212              
213             =back
214              
215             =head1 OPTIONS
216              
217             =over 4
218              
219             =item XmlOptions
220              
221             A hash reference to options passed to XML::Simple::XMLout to control the generation of the interstitial XML.
222             See L for a detailed description of all of the available options.
223              
224             =item VariableName
225              
226             Set the XML root element name in the interstitial XML. You can also achieve this by setting the
227             C or C options passed to XML::Simple in the C options
228             hash. This is a shortcut to make this renderer behave like some of the other
229             renderer backends.
230              
231             =item Template (aka TemplateFilename)
232              
233             Filename of XSL template. Mandatory unless TemplateString is defined.
234              
235             =item TemplateString
236              
237             String containing XSL template. Mandatory unless Template or TemplateFilename is defined.
238              
239             =item NoCache
240              
241             Disable in-memory caching of XSLTs loaded from the filesystem.
242              
243             =back
244              
245             =head1 GLOBAL VARIABLES
246              
247             The package-level template cache is created on demand the first time it's needed.
248             There are a few global variables which you can tune before it's created (i.e. before you create any objects):
249              
250             =over 4
251              
252             =item $Any::Renderer::XSLT::CacheMaxItems
253              
254             Maximum number of template objects held in the cache. Default is 1000.
255              
256             =item $Any::Renderer::XSLT::CacheMaxAtime
257              
258             Items older than this will be purged from the cache when the next purge() call happens. In Seconds. Default is 6 hours.
259              
260             =item $Any::Renderer::XSLT::CachePurgeInterval
261              
262             How often to purge the cache. In Seconds. Default is 1 hour.
263              
264             =back
265              
266             =head1 SEE ALSO
267              
268             L, L, L
269              
270             =head1 VERSION
271              
272             $Revision: 1.14 $ on $Date: 2006/09/04 12:15:53 $ by $Author: johna $
273              
274             =head1 AUTHOR
275              
276             Matt Wilson and John Alden
277              
278             =head1 COPYRIGHT
279              
280             (c) BBC 2006. This program is free software; you can redistribute it and/or modify it under the GNU GPL.
281              
282             See the file COPYING in this distribution, or http://www.gnu.org/licenses/gpl.txt
283              
284             =cut