From ac867ed8caaea3f90dc5998ecaaa746d2b5c0cc8 Mon Sep 17 00:00:00 2001 From: Marcel de Rooy Date: Fri, 19 Sep 2014 22:36:46 +0200 Subject: [PATCH] [PASSED QA] Bug 12973: Allow passing code to XSLT_Handler instead of filename This patch adds the option to pass a code string to the XSLT handler object instead of passing a filename. This is achieved by a change to parameter hashref. The old style parameters are also allowed. Note that this patch should not change behavior but will be used in future development: see bug 12758 or bug 12754. Test plan: Verify that behavior did not change in the following steps. [1] Edit OPACXSLTResultsDisplay in order to use XSLT. [2] Check search results page in OPAC. [3] Edit OPACXSLTDetailsDisplay in order to use XSLT. [4] Check detail page in OPAC. Signed-off-by: Martin Renvoize Signed-off-by: Kyle M Hall --- Koha/XSLT_Handler.pm | 86 +++++++++++++++++++++++++++++++++++++------------- 1 files changed, 64 insertions(+), 22 deletions(-) diff --git a/Koha/XSLT_Handler.pm b/Koha/XSLT_Handler.pm index 3b30ee8..0779f2f 100644 --- a/Koha/XSLT_Handler.pm +++ b/Koha/XSLT_Handler.pm @@ -26,6 +26,8 @@ Koha::XSLT_Handler - Facilitate use of XSLT transformations use Koha::XSLT_Handler; my $xslt_engine = Koha::XSLT_Handler->new; my $output = $xslt_engine->transform($xml, $xsltfilename); + $output = $xslt_engine->transform({ xml => $xml, file => $file }); + $output = $xslt_engine->transform({ xml => $xml, code => $code }); my $err= $xslt_engine->err; # error number my $errstr= $xslt_engine->errstr; # error message $xslt_engine->refresh($xsltfilename); @@ -129,6 +131,9 @@ __PACKAGE__->mk_accessors(qw( do_not_return_source print_warns )); =head2 transform my $output= $xslt_engine->transform( $xml, $xsltfilename ); + #Alternatively: + #$output = $xslt_engine->transform({ xml => $xml, file => $file }); + #$output = $xslt_engine->transform({ xml => $xml, code => $code }); if( $xslt_engine->err ) { #decide what to do on failure.. } @@ -136,6 +141,7 @@ __PACKAGE__->mk_accessors(qw( do_not_return_source print_warns )); Pass a xml string and a fully qualified path of a XSLT file. Instead of a filename, you may also pass a URL. + You may also pass the contents of a xsl file as a string like $code above. If you do not pass a filename, the last file used is assumed. Returns the transformed string. Check the error number in err to know if something went wrong. @@ -144,39 +150,43 @@ __PACKAGE__->mk_accessors(qw( do_not_return_source print_warns )); =cut sub transform { - my ( $self, $orgxml, $file ) = @_; + my $self = shift; + + #check parameters + # old style: $xml, $filename + # new style: $hashref + my ( $xml, $filename, $xsltcode ); + if( ref $_[0] eq 'HASH' ) { + $xml = $_[0]->{xml}; + $xsltcode = $_[0]->{code}; + $filename = $_[0]->{file} if !$xsltcode; #xsltcode gets priority + } else { + ( $xml, $filename ) = @_; + } #Initialized yet? if ( !$self->{xslt_hash} ) { $self->_init; } else { - $self->_set_error; #clear error + $self->_set_error; #clear last error } - my $retval = $self->{do_not_return_source} ? undef : $orgxml; + my $retval = $self->{do_not_return_source} ? undef : $xml; #check if no string passed - if ( !defined $orgxml ) { + if ( !defined $xml ) { $self->_set_error(7); return; #always undef } - #If no file passed, use the last file again - if ( !$file ) { - if ( !$self->{last_xsltfile} ) { - $self->_set_error(1); - return $retval; - } - $file = $self->{last_xsltfile}; - } - #load stylesheet - my $stsh = $self->{xslt_hash}->{$file} // $self->_load($file); + my $key = $self->_load( $filename, $xsltcode ); + my $stsh = $key? $self->{xslt_hash}->{$key}: undef; return $retval if $self->{err}; #parse input and transform my $parser = XML::LibXML->new(); - my $source = eval { $parser->parse_string($orgxml) }; + my $source = eval { $parser->parse_string($xml) }; if ($@) { $self->_set_error( 5, $@ ); return $retval; @@ -189,7 +199,7 @@ sub transform { $self->_set_error( 6, $@ ); return $retval; } - $self->{last_xsltfile} = $file; + $self->{last_xsltfile} = $key; return $str; } @@ -246,16 +256,42 @@ sub _init { # Internal routine for loading a new stylesheet. sub _load { - my ( $self, $file ) = @_; + my ( $self, $filename, $code ) = @_; + my ( $digest, $codelen, $salt, $rv ); + $salt = 'AZ'; #just a constant actually + + #If no file or code passed, use the last file again + if ( !$filename && !$code ) { + my $last = $self->{last_xsltfile}; + if ( !$last || !exists $self->{xslt_hash}->{$last} ) { + $self->_set_error(1); + return; + } + return $last; + } - if ( !$file || ( $file !~ /^https?:\/\// && !-e $file ) ) { + #check if it is loaded already + if( $code ) { + $codelen = length( $code ); + $digest = eval { crypt($code, $salt) }; + if( $digest && exists $self->{xslt_hash}->{$digest.$codelen} ) { + return $digest.$codelen; + } + } elsif( $filename && exists $self->{xslt_hash}->{$filename} ) { + return $filename; + } + + #Check file existence (skipping URLs) + if( $filename && $filename !~ /^https?:\/\// && !-e $filename ) { $self->_set_error(2); return; } #load sheet my $parser = XML::LibXML->new; - my $style_doc = eval { $parser->load_xml( location => $file ) }; + my $style_doc = eval { + $parser->load_xml( $self->_load_xml_args($filename, $code) ) + }; if ($@) { $self->_set_error( 3, $@ ); return; @@ -263,13 +299,19 @@ sub _load { #parse sheet my $xslt = XML::LibXSLT->new; - $self->{xslt_hash}->{$file} = eval { $xslt->parse_stylesheet($style_doc) }; + $rv = $code? $digest.$codelen: $filename; + $self->{xslt_hash}->{$rv} = eval { $xslt->parse_stylesheet($style_doc) }; if ($@) { $self->_set_error( 4, $@ ); - delete $self->{xslt_hash}->{$file}; + delete $self->{xslt_hash}->{$rv}; return; } - return $self->{xslt_hash}->{$file}; + return $rv; +} + +sub _load_xml_args { + my $self = shift; + return $_[1]? { 'string' => $_[1]//'' }: { 'location' => $_[0]//'' }; } # _set_error -- 1.7.2.5