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;