1 package Koha
::XSLT_Handler
;
3 # Copyright 2014 Rijksmuseum
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 3 of the License, or (at your option) any later
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License along
17 # with Koha; if not, write to the Free Software Foundation, Inc.,
18 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 Koha::XSLT_Handler - Facilitate use of XSLT transformations
26 use Koha::XSLT_Handler;
27 my $xslt_engine = Koha::XSLT_Handler->new;
28 my $output = $xslt_engine->transform($xml, $xsltfilename);
29 my $err= $xslt_engine->err; # error number
30 my $errstr= $xslt_engine->errstr; # error message
31 $xslt_engine->refresh($xsltfilename);
35 A XSLT handler object on top of LibXML and LibXSLT, allowing you to
36 run XSLT stylesheets repeatedly without loading them again.
37 Errors occurring during loading, parsing or transforming are reported
38 via the err and errstr attributes.
39 Reloading XSLT files can be done with the refresh method.
45 Create handler object (via Class::Accessor)
49 Run transformation for specific string and stylesheet
53 Allow to reload stylesheets when transforming again
59 Error number (see list of ERROR CODES)
65 =head2 do_not_return_source
67 If true, transform returns undef on failure. By default, it returns the
68 original string passed. Errors are reported as described.
72 If set, print error messages to STDERR. True by default.
86 Error while loading stylesheet xml: [furter information]
90 Error while parsing stylesheet: [furter information]
94 Error while parsing input: [furter information]
98 Error while transforming input: [furter information]
102 No string to transform
106 For documentation purposes. You are not encouraged to access them.
110 Contains the last successfully executed XSLT filename
114 Hash reference to loaded stylesheets
116 =head1 ADDITIONAL COMMENTS
124 use base
qw(Class::Accessor);
126 __PACKAGE__
->mk_ro_accessors(qw( err errstr ));
127 __PACKAGE__
->mk_accessors(qw( do_not_return_source print_warns ));
131 my $output= $xslt_engine->transform( $xml, $xsltfilename );
132 if( $xslt_engine->err ) {
133 #decide what to do on failure..
135 my $output2= $xslt_engine->transform( $xml2 );
137 Pass a xml string and a fully qualified path of a XSLT file.
138 Instead of a filename, you may also pass a URL.
139 If you do not pass a filename, the last file used is assumed.
140 Returns the transformed string.
141 Check the error number in err to know if something went wrong.
142 In that case do_not_return_source did determine the return value.
147 my ( $self, $orgxml, $file ) = @_;
150 if ( !$self->{xslt_hash
} ) {
154 $self->_set_error; #clear error
156 my $retval = $self->{do_not_return_source
} ?
undef : $orgxml;
158 #check if no string passed
159 if ( !defined $orgxml ) {
160 $self->_set_error(7);
161 return; #always undef
164 #If no file passed, use the last file again
166 if ( !$self->{last_xsltfile
} ) {
167 $self->_set_error(1);
170 $file = $self->{last_xsltfile
};
174 my $stsh = $self->{xslt_hash
}->{$file} // $self->_load($file);
175 return $retval if $self->{err
};
177 #parse input and transform
178 my $parser = XML
::LibXML
->new();
179 my $source = eval { $parser->parse_string($orgxml) };
181 $self->_set_error( 5, $@
);
185 my $result = $stsh->transform($source);
186 $stsh->output_as_chars($result);
189 $self->_set_error( 6, $@
);
192 $self->{last_xsltfile
} = $file;
198 $xslt_engine->refresh;
199 $xslt_engine->refresh( $xsltfilename );
201 Pass a file for an individual refresh or no file to refresh all.
202 Refresh returns the number of items affected.
203 What we actually do, is just clear the internal cache for reloading next
204 time when transform is called.
205 The return value is mainly theoretical. Since this is supposed to work
206 always(...), there is no actual need to test it.
207 Note that refresh does also clear the error information.
212 my ( $self, $file ) = @_;
214 return if !$self->{xslt_hash
};
217 $rv = delete $self->{xslt_hash
}->{$file} ?
1 : 0;
220 $rv = scalar keys %{ $self->{xslt_hash
} };
221 $self->{xslt_hash
} = {};
226 # ************** INTERNAL ROUTINES ********************************************
229 # Internal routine for initialization.
235 $self->{xslt_hash
} = {};
236 $self->{print_warns
} = 1 unless exists $self->{print_warns
};
237 $self->{do_not_return_source
} = 0
238 unless exists $self->{do_not_return_source
};
240 #by default we return source on a failing transformation
241 #but it could be passed at construction time already
246 # Internal routine for loading a new stylesheet.
249 my ( $self, $file ) = @_;
251 if ( !$file || ( $file !~ /^https?:\/\
// && !-e
$file ) ) {
252 $self->_set_error(2);
257 my $parser = XML
::LibXML
->new;
258 my $style_doc = eval { $parser->load_xml( location
=> $file ) };
260 $self->_set_error( 3, $@
);
265 my $xslt = XML
::LibXSLT
->new;
266 $self->{xslt_hash
}->{$file} = eval { $xslt->parse_stylesheet($style_doc) };
268 $self->_set_error( 4, $@
);
269 delete $self->{xslt_hash
}->{$file};
272 return $self->{xslt_hash
}->{$file};
276 # Internal routine for handling error information.
279 my ( $self, $errno, $addmsg ) = @_;
281 if ( !$errno ) { #clear the error
282 $self->{err
} = undef;
283 $self->{errstr
} = undef;
287 $self->{err
} = $errno;
289 $self->{errstr
} = "No XSLT file passed.";
291 elsif ( $errno == 2 ) {
292 $self->{errstr
} = "XSLT file not found.";
294 elsif ( $errno == 3 ) {
295 $self->{errstr
} = "Error while loading stylesheet xml:";
297 elsif ( $errno == 4 ) {
298 $self->{errstr
} = "Error while parsing stylesheet:";
300 elsif ( $errno == 5 ) {
301 $self->{errstr
} = "Error while parsing input:";
303 elsif ( $errno == 6 ) {
304 $self->{errstr
} = "Error while transforming input:";
306 elsif ( $errno == 7 ) {
307 $self->{errstr
} = "No string to transform.";
311 $self->{errstr
} .= " $addmsg";
314 warn $self->{errstr
} if $self->{print_warns
};
320 Marcel de Rooy, Rijksmuseum Netherlands