package Ernad::Xslt; use strict; use warnings; use Carp qw(confess); use XML::LibXML; use XML::LibXSLT; use Ernad::Files; use Ernad::Common; use Krichel::File; use base 'Ernad'; ## string as first param --> file ## doc as first param --> doc ## run gets the result ## chars transforms to chars ## text transforms to text sub transform_empty { my $x=shift; my $name=shift // confess "I need a name here."; my $string="\n"; my $doc = XML::LibXML->load_xml(string => $string); my $output=$x->transform($doc,$name); return $output; } ## get a stylesheet, formerly get_stylesheet sub get_sheet { my $x=shift; my $e=$main::e // $x->{'e'} // confess "I don't see the erimp."; my $name=shift or confess "no stylesheet name parameter"; if(defined($e->{'sheet'}->{$name})) { return $e->{'sheet'}->{$name}; } my $sheet=$x->read_stylesheet($name); $e->{'sheet'}->{$name}=$sheet; return $sheet; } sub read_stylesheet { my $x=shift; my $e=$main::e // $x->{'e'} // confess "I don't see the erimp."; my $name=shift or confess "I have no stylesheet name parameter"; my $style_dir=$e->{'dir'}->{'style'}; my $xslt_dir=$e->{'dir'}->{'xslt'}; my $sheet_file; ## normally the sheet is in style/impna, but can also be in xslt my $style_file=$style_dir.'/'.$name.$e->{'const'}->{'xsl_ext'}; my $xslt_file=$xslt_dir.'/'.$name.$e->{'const'}->{'xsl_ext'}; if(-f $style_file) { $sheet_file=$style_file; } elsif(-l $style_file) { $sheet_file=readlink $style_file; } elsif(-f $xslt_file) { $sheet_file=$xslt_file; } elsif(-l $xslt_file) { $sheet_file=readlink $xslt_file; } elsif(-f $name) { $sheet_file=$name; } elsif(not defined($sheet_file)) { confess "I don't have a sheet file for sheet '$name'"; } else { confess "I can't see the sheet file for sheet '$name' at '$sheet_file'"; } my $xslt=XML::LibXSLT->new(); $xslt->max_depth(1000000); ## version on trabbi does not have max_vars eval { $xslt->max_vars(1500000); }; if(not -f $sheet_file) { confess "I don't have $sheet_file"; } my $style_doc=XML::LibXML->load_xml('location'=>$sheet_file, 'no_cdata'=>1); my $sheet=$xslt->parse_stylesheet($style_doc); return $sheet; } ## FixMe: there should be one transform and one transform_to_text ## doc, sheet name sub run { my $x=shift; my $doc=shift or confess "I need a doc parameter."; if(not ref $doc eq 'XML::LibXML::Document') { confess "I see no document to transform."; } my $name=shift or confess "I need a stylesheet name."; my $e=$main::e // $x->{'e'} // confess "I don't see the erimp."; my $sheet=$x->get_sheet($name) or confess "I can't get stylesheet '$name'."; my $params=shift; my $results; if(defined($params)) { $results=$sheet->transform($doc, %$params); } else { $results=$sheet->transform($doc); } if($e->{'testing'}) { my $out_file=$e->{'dir'}->{'test'}."/transform_$name.xml"; &Krichel::File::prepare($out_file); $results->toFile($out_file); } return $results; } ## referenced in publish, has to stay for now sub transform { my $x=shift; my $e=$main::e // $x->{'e'} // confess "I don't see the erimp."; my $doc=shift or confess "I need a doc parameter."; if(not ref $doc eq 'XML::LibXML::Document') { confess "I see no document to transform."; } my $name=shift or confess "no name parameter"; my $sheet=$x->get_sheet($name) or confess; my $params=shift; my $results; if(defined($params)) { $results=$sheet->transform($doc, %$params); } else { $results=$sheet->transform($doc); } if($e->{'testing'}) { my $out_file=$e->{'dir'}->{'test'}."/transform_$name.xml"; &Krichel::File::prepare($out_file); $results->toFile($out_file); } return $results; } ## should go to e->x ## check first argument sub get_doc { my $x=shift; my $in=shift; my $in_ref=ref $in; if($in_ref eq 'XML::LibXML::Document') { return $in; } if(not (-f $in or -l $in)) { confess "I can not open your file '$in'"; } my $doc; eval { $doc=&Krichel::File::load($in); }; if(ref $doc ne 'XML::LibXML::Document') { confess "I can't parse your file '$in'"; } return $doc; } ## <-- new sub to_text { my $x=shift; my $in=shift // confess "I need an input to transform."; my $name=shift or confess "I don't have a stylsheet name parameter."; my $params=shift; my $doc=$x->get_doc($in); my $sheet=$x->get_sheet($name) // confess "I could not get the sheet $name"; my $results; if(defined($params)) { $results=$sheet->transform($doc, %$params); } else { $results=$sheet->transform($doc); } my $string=$sheet->output_as_bytes($results); return $string; } ## doc, sheet name, params (or params and type) sub t { my $x=shift; my $in=shift // confess "I don't have something to transform.\n"; ## accept an empty input my $doc; my $in_ref=ref $in; if($in eq '') { my $string="\n"; $doc = XML::LibXML->load_xml(string => $string); } elsif(not $in_ref) { if(not -f $in) { confess "I can't open your file '$in'."; } $doc=Krichel::File::load_xml($in); } elsif($in_ref ne 'XML::LibXML::Document') { confess "I want a document to transform, but I got a $in_ref.\n"; } else { $doc=$in; } my $name=shift or confess "I don't have a stylesheet name parameter."; my $after_name=shift; ## no params my $do='bytes'; my $out_file=''; my $params; my $ref_after_name=''; my $after_name_is_do = 0; if($after_name) { if(not $after_name) { $after_name_is_do = 1; $do='doc' } elsif($after_name eq 'chars') { $after_name_is_do = 1; $do='chars' } elsif($after_name eq 'bytes') { $after_name_is_do = 1; $do='bytes' } elsif($ref_after_name=ref($after_name)) { if($ref_after_name eq 'HASH') { $params = $after_name; } else { confess "I can't deal with a $ref_after_name\n"; } } $out_file=$after_name; if($out_file eq 'bytes') { #confess "out_file must not be 'bytes'"; ## emergency fix of 2019-06-19 $out_file = ''; } if(not $after_name_is_do and not -W $out_file) { confess "I can't write to your file '$out_file'."; } } my $final = shift; if(not $params) { my $ref_final=ref($final); #if(not $ref_final) { # $do=$final; #} if($ref_final eq 'HASH') { $params = $final; } #else { # confess "I can't handle this yet." #} } my $sheet=$x->get_sheet($name) or confess 'I can\'t get your stylesheet $name'; my $results; if(defined($params)) { $results=$sheet->transform($doc, %$params); } else { $results=$sheet->transform($doc); } if($do eq 'chars') { my $bytes=$sheet->output_as_bytes($results); return $bytes; } if($do eq 'chars' or $out_file) { my $chars=$sheet->output_as_chars($results); if(not $out_file) { return $chars; } return Ernad::Files::save_if_diff($out_file,$chars); } else { return $results; } return $sheet; } # ## doc, sheet name 2016-12-29 for use with slurper # sub transform_to_chars { # my $x=shift; # my $doc=shift or confess "I don't have something to transform.\n"; # my $doc_ref=ref $doc; # if(not $doc_ref) { # confess "You gave me a string to transform. I need a document."; # } # if(not $doc_ref eq 'XML::LibXML::Document') { # confess "I want a document to transform, but got a $doc_ref.\n"; # } # my $name=shift or confess "I don't have a stylsheet name parameter."; # my $params=shift; # my $sheet=$x->get($name) or confess; # my $results; # if(defined($params)) { # $results=$sheet->transform($doc, %$params); # } # else { # $results=$sheet->transform($doc); # } # my $string=$sheet->output_as_chars($results); # return $string; # } ## doc, sheet name sub transform_file { my $x=shift; my $file=shift or confess "no doc parameter"; if(not -f $file) { confess "no such file '$file'"; } my $name=shift or confess "no stylesheet name parameter"; my $params=shift; my $doc=&Krichel::File::load($file); return $x->transform($doc,$name,$params); } # ## doc, sheet name # sub transform_file_to_text { # my $x=shift; # my $file=shift or confess "I have no file (first) parameter"; # if(not -f $file) { # confess "no such file '$file'"; # } # my $name=shift or confess "no stylesheet name parameter"; # my $params=shift; # my $doc=&Ernad::Common::load_and_return_xml($file); # return $x->transform_to_text($doc,$name,$params); # } 1;