package Template;
use strict;
use JFile;
use CSV;
sub new
{
my ($module, @a) = @_;
my $this = {};
bless $this;
for(my $i = 0 ; $i < @a ; $i += 2) {
my $key = $a[$i];
my $val = $a[$i+1];
$key =~ s/^-//;
$this->{$key} = $val;
}
return $this;
}
sub InvalidateBraKet
{
my ($str, $bra, $ket) = @_;
$bra = '{' if(!defined $bra);
$ket = '}' if(!defined $ket);
my $bracode = Utils::ChrToHTMLCode($bra);
my $ketcode = Utils::ChrToHTMLCode($ket);
$str =~ s/$bra/$bracode/gsi;
$str =~ s/$ket/$ketcode/gsi;
return $str;
}
sub ReadExcelTemplate
{
my ($this, $TemplatePath, $key) = @_;
return $this->ReadHTMLTemplate($TemplatePath, $key);
}
sub ReadHTMLTemplate
{
my ($this, $TemplatePath, $key) = @_;
$key = "\\{sn\\}" if(!defined $key);
$this->{TemplatePath} = $TemplatePath if(defined $TemplatePath);
my $content = JFile->new()->ReadFile($TemplatePath, undef, "r");
return undef if(!$content);
my ($head, $template, $tail) = ('', '', $content);
while(1) {
my ($s1, $s2, $s3) = ($tail =~ /^(.*?)(
)(.*)$/si);
last if(!defined $s1);
if($s2 =~ /$key/) {
$template = $s2;
$head .= $s1;
$tail = $s3;
last
}
else {
$head .= $s1 . $s2;
$tail = $s3;
}
}
$head =~ s/(.*?)<\/span>/$1/sg;
$template =~ s/(.*?)<\/span>/$1/sg;
$tail =~ s/(.*?)<\/span>/$1/sg;
$head =~ s/%7B/{/i;
$head =~ s/%7D/}/i;
$template =~ s/%7B/{/i;
$template =~ s/%7D/}/i;
$tail =~ s/%7B/{/i;
$tail =~ s/%7D/}/i;
#print "h [$head]
\n";
return ($head, $template, $tail);
}
sub ReadCSVTemplate
{
my ($this, $TemplatePath, $key) = @_;
$key = "\\{sn\\}" if(!defined $key);
$this->{TemplatePath} = $TemplatePath if(defined $TemplatePath);
my $content = JFile->new()->ReadFile($TemplatePath, undef, "r");
return undef if(!$content);
my ($head, $template, $tail) = ('', '', $content);
while(1) {
my ($s1, $s2, $s3) = ($tail =~ /^(.*?)(.*?[\r\n]+)(.*)$/si);
last if(!defined $s1);
if($s2 =~ /$key/) {
$template = $s2;
$head .= $s1;
$tail = $s3;
last
}
else {
$head .= $s1 . $s2;
$tail = $s3;
}
}
return ($head, $template, $tail);
}
sub ReadTemplate
{
my ($this, $TemplatePath, $LineKey) = @_;
$this->{TemplatePath} = $TemplatePath if(defined $TemplatePath);
$LineKey = $this->{LineKey} if(!defined $LineKey);
$this->{Template} = JFile->new()->ReadFile($this->{TemplatePath}) or return undef;
# に{:Start}タグがあり、それによって背景の表示がページごとにうまくいっている
# $this->{Template} =~ s/\]*?\>.*?\<\/title[^\>]*?\>//;
my ($nRepeat, $pNumbered, $pNonNumbered) = $this->ParseTemplate($this->{Template});
if(defined $this->{Type} and $this->{Type} eq 'HTML') {
($this->{TemplateHeader}, $this->{TemplatePage}, $this->{TemplateTail})
= $this->ReadHTMLTemplate($this->{TemplatePath}, $LineKey);
}
elsif(defined $this->{Type} and $this->{Type} eq 'CSV') {
($this->{TemplateHeader}, $this->{TemplatePage}, $this->{TemplateTail})
= $this->ReadCSVTemplate($this->{TemplatePath}, $LineKey);
}
elsif(defined $this->{Type} and $this->{Type} eq 'Excel') {
($this->{TemplateHeader}, $this->{TemplatePage}, $this->{TemplateTail})
= $this->ReadExcelTemplate($this->{TemplatePath}, $LineKey);
}
else {
my $KeyPageStart = $this->{KeyPageStart};
my $KeyPageEnd = $this->{KeyPageEnd};
if(defined $KeyPageStart and defined $KeyPageEnd) {
($this->{TemplateHeader}, $this->{TemplatePage}, $this->{TemplateTail})
= ($this->{Template} =~ /^(.*?)$KeyPageStart(.*)$KeyPageEnd(.*?)$/si);
}
}
if($this->{DeleteHeader}) {
$this->{TemplateHeader} =~ s/^.*\<\s*body[^\>]*\>\s*//si;
$this->{TemplateTail} =~ s/\s*\<\/\s*body[^\>]*\>.*$//si;
}
if($this->{CharCode} ne '') {
Jcode::convert(\$this->{TemplateHeader}, $this->{CharCode});
Jcode::convert(\$this->{TemplatePage}, $this->{CharCode});
Jcode::convert(\$this->{TemplateTail}, $this->{CharCode});
}
$this->{nRepeat} = $nRepeat if(!defined $this->{nRepeat});
#print "nRepeat=$nRepeat
\n";
return $this->{Template};
}
sub ParseTemplate
{
my ($this, $text) = @_;
$text = $this->{Template} if(!defined $text);
#print "text: [$text]\n";
my @a = ($text =~ /{[\w\d]+?}/g);
my (%Numbered, %NonNumbered);
my $nMaxIndex = 0;
foreach my $s (@a) {
#print "$s\n";
if($s =~ /^\{(.+?)(\d+)\}$/) {
my $key = $1;
my $i = $2;
$nMaxIndex = $i if($i > $nMaxIndex);
$Numbered{$key}++;
}
else {
$NonNumbered{$s}++;
}
}
if(0) {
print "nMaxIndex: $nMaxIndex
\n";
foreach my $key (keys %Numbered) {
print "Nubmered: $key
\n";
}
foreach my $key (keys %NonNumbered) {
print "NonNubmered: $key
\n";
}
}
$nMaxIndex = $this->{nRepeat} if(defined $this->{nRepeat});
return ($nMaxIndex, [keys %Numbered], [keys %NonNumbered]);
}
sub ReadIndex
{
my ($this) = @_;
$this->{IndexCSV} = new CSV;
$this->{IndexCSV}->Read($this->{IndexPath}, 0, 0) or return undef;
return $this->{IndexCSV};
}
sub ReplaceByHash
{
my ($this, $text, $pHash, $bra, $ket, $ExtractHTMLBody, $CharCode,
$ShowError, $InvalidateHTMLTags, $RemoveUndefined, $ReplaceRegExp) = @_;
#print "$ket, $ExtractHTMLBody, $CharCode, $ShowError, $InvalidateHTMLTags, $RemoveUndefined, $ReplaceRegExp
\n";
$InvalidateHTMLTags = 0 if(!defined $InvalidateHTMLTags);
$RemoveUndefined = 1 if(!defined $RemoveUndefined);
$ReplaceRegExp = 0 if(!defined $ReplaceRegExp);
if($ExtractHTMLBody) {
($text) = ($text =~ /]*>(.*)<\/body[^>]*>/si);
}
$CharCode = 'utf8' if($CharCode =~ /utf-8/i);
my $Convert = ($CharCode =~ /(jp|jis|utf)/i)? 1 : 0;
if($Convert) {
Jcode::convert(\$text, $CharCode);
}
#print("LogonMessage[$pHash->{LogonMessage_jp}]
\n");
foreach my $key (sort keys %$pHash) {
# foreach my $key (sort { length($a) <=> length($b); } keys %$pHash) {
my $val = $pHash->{$key};
$val =~ s/$bra/_br$bra\_/sg;
$val =~ s/$ket/_br$ket\_/sg;
#$val =~ s/${bra}/_br${bra}_/sg;
#$val =~ s/${ket}/_br${ket}_/sg;
#print "$key
\n";
#print "$key: $val
\n";
if($Convert) {
Jcode::convert(\$val, $CharCode);
}
Utils::InvalidateHTMLTags($val) if($InvalidateHTMLTags);
$key = Utils::RegExpQuote($key);
#$val = Utils::URLDecode($val);
if($key =~ /^\d/) {
$text =~ s/\\$bra$key\\$ket/$val/sg;
}
else {
$text =~ s/$bra$key$ket/$val/sg;
}
}
if($RemoveUndefined and defined $bra and defined $ket) {
$text =~ s/$bra[\$_\w]+$ket//sg;
}
$bra =~ s/\{/\\{/g;
$ket =~ s/\}/\\}/g;
$text =~ s/_br$bra\_/$bra/sg;
$text =~ s/_br$ket\_/$ket/sg;
#$text =~ s/_br${bra}_/$bra/sg;
#$text =~ s/_br${ket}_/$ket/sg;
#print "val: $text
\n";
if($ReplaceRegExp) {
$text =~ s/\\\\/\\/g;
$text =~ s/\\'/'/g;
$text =~ s/\\"/"/g;
$text =~ s/\\\?/\?/g;
$text =~ s/\\n/\n/g;
$text =~ s/\\r/\r/g;
$text =~ s/\\t/\t/g;
$text =~ s/\\\/\>/g;
}
#print "t[$text]\n";
return $text;
}
sub GetTextByHash
{
my ($this, $TemplatePath, $pHash, $bra, $ket, $ExtractHTMLBody, $CharCode,
$ShowError, $InvalidateHTMLTags, $RemoveUndefined, $ReplaceRegExp) = @_;
#Utils::InitHTML();
#print "cc: [$CharCode]
\n";
my $text = $this->ReadTemplate($TemplatePath);
#print "cc2: [$CharCode]
\n";
if($ShowError and !defined $text) {
print "Error in Template::GetTextByHash: Can not read [$TemplatePath].\n";
return undef;
}
#print "cc3: [$CharCode]
\n";
#print "aa [$pHash][$TemplatePath]
";
$text = $this->ReplaceByHash($text, $pHash, $bra, $ket, $ExtractHTMLBody,
$CharCode, $ShowError, $InvalidateHTMLTags, $RemoveUndefined, $ReplaceRegExp);
#my $text2 = Utils::InvalidateHTMLTags($text);
#print "cc4: [$CharCode]
[$text2]
\n";
return $text;
}
sub SaveTo
{
my ($this, $OutputPath, $pConvertCallbackFunc) = @_;
my $out = new JFile($OutputPath, "w") or return undef;
my $ret = $this->SaveToWithOutputHandle($out, $pConvertCallbackFunc);
$out->Close();
return $ret;
}
sub SaveToWithOutputHandle
{
my ($this, $out, $pConvertCallbackFunc, $pDefaultReplaceHash) = @_;
#print "cf: $pConvertCallbackFunc
\n";
if(!defined $this->{Template}) {
$this->ReadTemplate() or return undef;
}
if(defined $this->{IndexPath} and !defined $this->{IndexCSV}) {
$this->ReadIndex() or return undef;
}
my $nRepeat = $this->{nRepeat};
$nRepeat = 1 if($nRepeat == 0);
my $TemplateHeader = $this->{TemplateHeader};
my $TemplatePage = $this->{TemplatePage};
my $TemplateTail = $this->{TemplateTail};
my $KeyPageStart = $this->{KeyPageStart};
my $KeyPageEnd = $this->{KeyPageEnd};
#print "h [", Utils::InvalidateHTMLTags($TemplateHeader), "]
\n";
#print "p [", Utils::InvalidateHTMLTags($TemplatePage), "]
\n";
#print "t [", Utils::InvalidateHTMLTags($TemplateTail), "]
\n";
my $csv = $this->{IndexCSV};
# my $nArray = $csv->nDataArray();
my $nData;
if($csv) {
$nData = $csv->nData();
}
else {
$nData = $this->{pDatabase}->nHit();
}
#print("$nData found (nRepeat=$nRepeat).
\n");
#print "header [$TemplateHeader]
\n";
#print "template body [$TemplatePage]
\n";
#print "tail [$TemplateTail]
\n";
Utils::ConvertString($TemplateHeader, "{%key%}", %$pDefaultReplaceHash);
$out->print($TemplateHeader);
my $count = 0;
for(my $i = 0 ; $i < $nData ; ) {
my %ReplaceHash;
#print "i=$i,$nRepeat
\n";
my $DoOutput = 0;
for(my $j = 0 ; $j < $nRepeat ; ) {
my $pHash;
#print "i=$i,$j,$count [$nData]
\n";
last if($count >= $nData);
if($csv) {
$pHash = $csv->GetHashData($count);
}
else {
%$pHash = $this->{pDatabase}->GetNextHit();
}
$count++;
#foreach my $key (keys %$pHash) {
# $out->print("$key: $pHash->{$key}\n");
#}
if($pConvertCallbackFunc) {
if(&$pConvertCallbackFunc($this, $pHash, $this->{CharCode})) {
$DoOutput = 1;
#print("Fee[$pHash->{RegistrationFee}]
\n");
}
else {
next;
}
}
else {
$DoOutput = 1;
}
if($j == 0) {
foreach my $key (keys %$pHash) {
#print("Fee2[$pHash->{RegistrationFee}]
\n") if($key eq 'RegistrationFee');
$ReplaceHash{$key} = $pHash->{$key};
}
}
my $j1 = $j + 1;
foreach my $key (keys %$pHash) {
#print("Fee2[$pHash->{RegistrationFee}]
\n") if($key eq 'RegistrationFee');
$ReplaceHash{"${key}$j1"} = $pHash->{$key};
}
$j++;
$i++;
}
if($DoOutput) {
my $s = $TemplatePage;
Utils::ConvertString($s, "{%key%}", %ReplaceHash);
# ファイル先頭に{:Start}タグを書くと、にも同じタグが入り、それによって背景の表示がページごとにうまくいっている
# ただし{:Start}タグが本文にでもでてくるので、それを削除する
$s =~ s/$KeyPageStart//g if($KeyPageStart ne '');
#$s =~ s/$KeyPageEnd//g;
#print "bb [$s]
\n";
$out->print($s);
}
last if($count >= $nData);
}
#print "t [$TemplateTail]
\n";
Utils::ConvertString($TemplateTail, "{%key%}", %$pDefaultReplaceHash);
$out->print($TemplateTail);
return 1;
}
1;