From: Patrick Canterino Date: Fri, 2 Dec 2011 20:07:26 +0000 (+0000) Subject: Template-Klasse 2.5 hinzugefuegt X-Git-Tag: 2.5~1 X-Git-Url: https://git.p6c8.net/template-class.git/commitdiff_plain/86d4aac26dbd34db74571787559940c56f6e3f26 Template-Klasse 2.5 hinzugefuegt --- 86d4aac26dbd34db74571787559940c56f6e3f26 diff --git a/Template.pm b/Template.pm new file mode 100644 index 0000000..eb13acb --- /dev/null +++ b/Template.pm @@ -0,0 +1,993 @@ +package Template; + +# +# Template (Version 2.5) +# +# Klasse zum Parsen von Templates +# +# Autor: Patrick Canterino +# Letzte Aenderung: 25.11.2011 +# +# Copyright (C) 2002-2011 Patrick Canterino +# +# Diese Datei kann unter den Bedingungen der "Artistic License 2.0" +# weitergegeben und / oder veraendert werden. +# Siehe: +# http://www.opensource.org/licenses/artistic-license-2.0 +# + +use strict; + +use Carp qw(croak); +use File::Spec; + +# new() +# +# Konstruktor +# +# Parameter: -keine- +# +# Rueckgabe: Template-Objekt + +sub new { + my $class = shift; + my $self = {file => '', template => '', original => '', old_parsing => 0, vars => {}, defined_vars => [], loop_vars => {}}; + return bless($self,$class); +} + +# get_template() +# +# Kompletten Vorlagentext zurueckgeben +# +# Parameter: -keine- +# +# Rueckgabe: Kompletter Vorlagentext (String) + +sub get_template { + return shift->{'template'}; +} + +# set_template() +# +# Kompletten Vorlagentext aendern +# +# Parameter: Vorlagentext +# +# Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + +sub set_template($) { + my ($self,$template) = @_; + $self->{'template'} = $template; +} + +# add_text() +# +# Vorlagentext ans Template-Objekt anhaengen +# +# Parameter: Vorlagentext +# +# Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + +sub add_text($) { + my ($self,$text) = @_; + $self->set_template($self->get_template.$text); +} + +# read_file() +# +# Einlesen einer Vorlagendatei und {INCLUDE}-Anweisungen ggf. verarbeiten +# (Text wird an bereits vorhandenen Text angehaengt) +# +# Parameter: 1. Datei zum Einlesen +# 2. Status-Code (Boolean): +# true => {INCLUDE}-Anweisungen nicht verarbeiten +# false => {INCLUDE}-Anweisungen verarbeiten (Standard) +# +# Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + +sub read_file($;$) { + my ($self,$file,$not_include) = @_; + local *FILE; + + $self->{'file'} = $file; + + open(FILE,'<'.$file) or croak "Open $file: $!"; + read(FILE, my $content, -s $file); + close(FILE) or croak "Closing $file: $!"; + + $self->add_text($content); + $self->save_state; + + $self->parse_includes unless($not_include); +} + +# set_var() +# +# Wert einer Variable setzen +# +# Parameter: 1. Name der Variable +# 2. Wert, den die Variable erhalten soll +# +# Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + +sub set_var($$) { + my ($self,$var,$content) = @_; + $self->{'vars'}->{$var} = $content; +} + +# get_var() +# +# Wert einer Variable zurueckgeben +# +# Parameter: (optional) Variablenname +# +# Rueckgabe: Wert der Variable; +# wenn die Variable nicht existiert, false; +# wenn kein Variablenname angegeben wurde, wird ein +# Array mit den Variablennamen zurueckgegeben + +sub get_var(;$) { + my ($self,$var) = @_; + + if(defined $var) { + if($self->{'vars'}->{$var}) { + return $self->{'vars'}->{$var}; + } + else { + return undef; + } + } + else { + return keys %{$self->{'vars'}}; + } +} + +# set_vars() +# +# Komplettes Variablen-Array mit einem anderen Array ueberschreiben +# +# Parameter: Array +# +# Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + +sub set_vars($) { + my ($self,$vars) = @_; + $self->{'vars'} = $vars; +} + +# add_vars() +# +# Zum bestehenden Variablen-Array weitere Variablen in Form eines Arrays +# hinzufuegen +# +# Parameter: Array +# +# Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + +sub add_vars($) { + my ($self,$vars) = @_; + $self->{'vars'} = {(%{$self->{'vars'}}, %$vars)}; + + #while(my ($name,$content) = each(%$vars)) { + # $self->{'vars'}->{$name} = $content; + #} +} + +# set_loop_data() +# +# Daten fuer eine Schleife setzen +# +# Parameter: 1. Name der Schleife +# 2. Array-Referenz mit den Hash-Referenzen mit +# den Variablen fuer die Schleifendurchgaenge +# +# Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + +sub set_loop_data($$) { + my ($self,$loop,$data) = @_; + $self->{'loop_vars'}->{$loop} = $data; +} + +# add_loop_data() +# +# Daten fuer einen Schleifendurchgang hinzufuegen +# +# Parameter: 1. Name der Schleife +# 2. Hash-Referenz mit den Variablen fuer den +# Schleifendurchgang +# +# Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + +sub add_loop_data($$) { + my ($self,$loop,$data) = @_; + + if($self->{'loop_vars'}->{$loop} && ref($self->{'loop_vars'}->{$loop}) eq 'ARRAY') { + push(@{$self->{'loop_vars'}->{$loop}},$data); + } + else { + $self->{'loop_vars'}->{$loop} = [$data]; + } +} + +# parse() +# +# In der Template definierte Variablen auslesen, Variablen +# ersetzen, {IF}- und {TRIM}-Bloecke parsen +# +# Parameter: -nichts- +# +# Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + +sub parse { + my $self = shift; + return $self->parse_old if($self->{'old_parsing'}); + + # Zuerst die Schleifen parsen + + if($self->{'loop_vars'} && (my @loops = keys(%{$self->{'loop_vars'}}))) { + foreach my $loop(@loops) { + $self->parse_loop($loop); + } + } + + # In Template-Datei definierte Variablen auslesen + + $self->get_defined_vars; + + # Variablen ersetzen + + my @vars = $self->get_var; + + if(defined(@vars) && scalar(@vars) > 0) { + $self->parse_if_blocks; + $self->replace_vars; + } + + # {TRIM}-Bloecke entfernen + + $self->parse_trim_blocks; +} + +# parse_old() +# +# In der Template definierte Variablen auslesen, Variablen +# ersetzen, {IF}- und {TRIM}-Bloecke parsen +# (alte Methode) +# +# Parameter: -nichts- +# +# Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + +sub parse_old { + my $self = shift; + + # Zuerst die Schleifen parsen + + if($self->{'loop_vars'} && (my @loops = keys(%{$self->{'loop_vars'}}))) { + foreach my $loop(@loops) { + $self->parse_loop($loop); + } + } + + # Normale Variablen durchgehen + + foreach my $var($self->get_var) { + my $val = $self->get_var($var); + + $self->parse_if_block($var,$val); + + if(ref($val) eq 'ARRAY') { + $self->fillin_array($var,$val); + } + else { + $self->fillin($var,$val); + } + } + + # Jetzt dasselbe mit denen, die direkt in der Template-Datei definiert + # sind, machen. Ich weiss, dass das eine ziemlich unsaubere Loesung ist, + # aber es funktioniert + + $self->get_defined_vars; + + foreach my $var(@{$self->{'defined_vars'}}) { + my $val = $self->get_var($var); + + $self->parse_if_block($var,$val); + $self->fillin($var,$val); + } + + # {TRIM}-Bloecke entfernen + + $self->parse_trim_blocks; +} + +# fillin() +# +# Variablen durch Text ersetzen +# +# Parameter: 1. Variable zum Ersetzen +# 2. Text, durch den die Variable ersetzt werden soll +# +# Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + +sub fillin($$) { + my ($self,$var,$text) = @_; + + $text = '' unless defined $text; # Um Fehler zu vermeiden + + my $template = $self->get_template; + $template = str_replace('{'.$var.'}',$text,$template); + + $self->set_template($template); +} + +# fillin_array() +# +# Variable durch Array ersetzen +# +# Parameter: 1. Variable zum Ersetzen +# 2. Array-Referenz, durch die die Variable ersetzt werden soll +# 3. Zeichenkette, mit der das Array verbunden werden soll +# (Standard: '') +# +# Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + +sub fillin_array($$;$) { + my ($self,$var,$array,$glue) = @_; + $glue = '' unless defined $glue; + + $self->fillin($var,join($glue,@$array)); +} + +# replace_vars() +# +# Variablen eine nach der anderen ersetzen. Sollte in einer Variable eine +# andere Variable auftauchen, so wird diese nicht ersetzt. +# +# Parameter: Array mit zu parsenden Variablen (optional) +# +# Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + +sub replace_vars(;@) { + my ($self,@valid) = @_; + my $template = $self->get_template; + + my @valid_vars = (@valid) ? @valid : $self->get_var; + + for(my $x=0;$xget_var($var); + + if(ref($val) eq 'ARRAY') { + $content = join('',@$val); + } + else { + $content = $val; + } + + # Daten vor und nach der Variable + + my $pre = substr($template,0,$x); + my $post = substr($template,length($pre)+2+length($var)); + + # Alles neu zusammensetzen + + $template = $pre.$content.$post; + + # Zaehler aendern + + $x = length($pre.$content)-1; + } + } + } + } + + $self->set_template($template); +} + +# to_file() +# +# Template in Datei schreiben +# +# Parameter: Datei-Handle +# +# Rueckgabe: Status-Code (Boolean) + +sub to_file($) { + my ($self,$handle) = @_; + return print $handle $self->get_template; +} + +# reset() +# +# Den gesicherten Stand des Template-Textes wiederherstellen +# +# Parameter: -nichts- +# +# Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + +sub reset { + my $self = shift; + $self->{'template'} = $self->{'original'}; +} + +# save_state() +# +# Aktuellen Stand des Template-Textes sichern +# (alte Sicherung wird ueberschrieben) +# +# Parameter: -nichts- +# +# Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + +sub save_state { + my $self = shift; + $self->{'original'} = $self->{'template'}; +} + +# parse_loop() +# +# Eine Schleife parsen +# +# Parameter: Name der Schleife +# +# Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + +sub parse_loop($) { + my ($self,$name) = @_; + + my $template = $self->get_template; + return if(index($template,'{LOOP '.$name.'}') == -1); + + my $offset = 0; + my $name_len = length($name); + + while((my $begin = index($template,'{LOOP '.$name.'}',$offset)) != -1) { + if((my $end = index($template,'{ENDLOOP}',$begin+6+$name_len)) != -1) { + my $block = substr($template,$begin,$end+9-$begin); + my $content = substr($block,$name_len+7,-9); + + my $parsed_block = ''; + + for(my $x=0;$x{'loop_vars'}->{$name}};$x++) { + my $loop_data = $self->{'loop_vars'}->{$name}->[$x]; + my @loop_vars = keys(%$loop_data); + + my $ctpl = new Template; + $ctpl->set_template($content); + + foreach my $loop_var(@loop_vars) { + $ctpl->set_var($name.'.'.$loop_var,$loop_data->{$loop_var}); + } + + if($self->{'old_parsing'}) { + $ctpl->parse_old; + } + else { + $ctpl->parse; + } + + $parsed_block .= $ctpl->get_template; + + undef($ctpl); + } + + $template = str_replace($block,$parsed_block,$template); + $offset = $begin+length($parsed_block); + } + else { + last; + } + } + + $self->set_template($template); +} + +# get_defined_vars() +# +# In der Template-Datei definierte Variablen auslesen +# +# Parameter: -nichts- +# +# Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + +sub get_defined_vars { + my $self = shift; + + my $template = $self->get_template; + return if(index($template,'{DEFINE ') == -1); + + my $offset = 0; + + while(index($template,'{DEFINE ',$offset) != -1) { + my $begin = index($template,'{DEFINE ',$offset)+8; + $offset = $begin; + + my $name = ''; + my $content = ''; + + my $var_open = 0; + my $name_found = 0; + my $define_block = 0; + + for(my $x=$begin;$xget_var($name)) { + # Die Variable wird nur gesetzt, wenn sie nicht bereits gesetzt ist + + $self->set_var($name,$content); + push(@{$self->{'defined_vars'}},$name); + } + + # {DEFINE}-Block entfernen + + my $pre = substr($template,0,$begin-8); + my $post = substr($template,$x+2); + + $template = $pre.$post; + + # Fertig! + + $offset = length($pre); + last; + } + } + elsif(substr($template,$x,1) eq '\\') { + # Ein Backslash wurde gefunden, er dient zum Escapen von Zeichen + + if(substr($template,$x+1,1) eq 'n') { + # "\n" in Zeilenumbrueche umwandeln + + $content .= "\n"; + } + else { + $content .= substr($template,$x+1,1); + } + + $x++; + } + else { + $content .= substr($template,$x,1); + } + } + else { + if($name_found == 1) { + if($var_open == 0) { + if(substr($template,$x,1) eq '"') { + $var_open = 1; + } + else { + last; + } + } + } + else { + # Variablennamen auslesen + + if(substr($template,$x,1) eq '}' && $name ne '') { + # Wir haben einen {DEFINE}-Block + + $name_found = 1; + $define_block = 1; + + # Alles ab hier sollte mit dem Teil verbunden werden, der das + # {DEFINE} in einer Zeile verarbeitet + + # Der Parser fuer {DEFINE}-Bloecke ist nicht rekursiv, was auch + # nicht noetig sein sollte + + if((my $end = index($template,'{ENDDEFINE}',$x)) != -1) { + $x++; + + $content = substr($template,$x,$end-$x); + + if(not defined $self->get_var($name)) { + # Die Variable wird nur gesetzt, wenn sie nicht bereits gesetzt ist + + $self->set_var($name,$content); + push(@{$self->{'defined_vars'}},$name); + } + + my $pre = substr($template,0,$begin-8); + my $post = substr($template,$end+11); + + $template = $pre.$post; + + # Fertig! + + $offset = length($pre); + last; + } + else { + last; + } + } + elsif(substr($template,$x,1) ne ' ') { + $name .= substr($template,$x,1); + } + elsif(substr($template,$x,1) ne '') { + $name_found = 1; + } + else { + last; + } + } + } + } + } + + $self->set_template($template); +} + +# parse_if_block() +# +# IF-Bloecke verarbeiten +# +# Parameter: 1. Name des IF-Blocks (das, was nach dem IF steht) +# 2. Status-Code (true => Inhalt anzeigen +# false => Inhalt nicht anzeigen +# 3. true => Verneinten Block nicht parsen +# false => Verneinten Block parsen (Standard) +# +# Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + +sub parse_if_block($$;$) { + my ($self,$name,$state,$no_negate) = @_; + my $template = $self->get_template; + + my $count = 0; + + while(index($template,'{IF '.$name.'}') >= 0) { + # Das alles hier ist nicht wirklich elegant geloest... + # ... aber solange es funktioniert... ;-) + + $count++; + + my $start = index($template,'{IF '.$name.'}'); + my $tpl_tmp = substr($template,$start); + my @splitted = explode('{ENDIF}',$tpl_tmp); + + my $block = ''; # Kompletter bedingter Block + my $ifs = 0; # IF-Zaehler (wird fuer jedes IF erhoeht und fuer jedes ENDIF erniedrigt) + + # {IF} + + for(my $x=0;$x<@splitted;$x++) { + croak 'Nesting error found while parsing IF block "'.$name.'" nr. '.$count.' in template file "'.$self->{'file'}.'"' if($x == $#splitted); + + $ifs += substr_count($splitted[$x],'{IF '); # Zum Zaehler jedes Vorkommen von IF hinzuzaehlen + $ifs--; # Zaehler um 1 erniedrigen + $block .= $splitted[$x].'{ENDIF}'; # Daten zum Block hinzufuegen + + if($ifs == 0) { + # Zaehler wieder 0, also haben wir das Ende des IF-Blocks gefunden :-)) + + last; + } + } + + my $if_block = substr($block,length($name)+5,-7); # Alles zwischen {IF} und {ENDIF} + + # {ELSE} + + my $else_block = ''; # Alles ab {ELSE} + $ifs = 0; # IF-Zaehler + + @splitted = explode('{ELSE}',$if_block); + + for(my $x=0;$x<@splitted;$x++) { + $ifs += substr_count($splitted[$x],'{IF '); # Zum Zaehler jedes Vorkommen von IF hinzuzaehlen + $ifs -= substr_count($splitted[$x],'{ENDIF}'); # Vom Zaehler jedes Vorkommen von ENDIF abziehen + + if($ifs == 0) { + # Zaehler 0, also haben wir das Ende des IF-Abschnitts gefunden + + # Aus dem Rest den ELSE-Block zusammenbauen + + for(my $y=$x+1;$y<@splitted;$y++) { + $else_block .= '{ELSE}'.$splitted[$y]; + } + + if($else_block) { + $if_block = substr($if_block,0,length($if_block)-length($else_block)); + $else_block = (length($else_block) > 6) ? substr($else_block,6) : ''; # Ansonsten gibt es Fehler + } + + last; + } + } + + my $replacement = ($state) ? $if_block : $else_block; + + $template = str_replace($block,$replacement,$template); + } + + $self->set_template($template); + + # Evtl. verneinte Form parsen + + unless($no_negate) { + $self->parse_if_block('!'.$name,not($state),1); + } +} + +# parse_if_blocks() +# +# IF-Bloecke zu allen definierten Variablen verarbeiten +# +# Parameter: Array mit zu verarbeitenden IF-Bloecken (optional) +# +# Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + +sub parse_if_blocks(;@) { + my ($self,@valid) = @_; + + my @valid_vars = (@valid) ? @valid : $self->get_var; + + foreach my $valid_var(@valid_vars) { + $self->parse_if_block($valid_var,$self->get_var($valid_var)); + } +} + +# parse_trim_blocks() +# +# {TRIM}-Bloecke parsen +# +# Dieser Parser ist nicht rekursiv, was auch nicht +# noetig sein sollte. +# +# Parameter: -nichts- +# +# Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + +sub parse_trim_blocks { + my $self = shift; + + my $template = $self->get_template; + return if(index($template,'{TRIM}') == -1); + + my $offset = 0; + + while((my $begin = index($template,'{TRIM}')) >= 0) { + if((my $end = index($template,'{ENDTRIM}',$begin+6)) >= 0) { + my $block = substr($template,$begin,$end+9-$begin); + my $content = substr($block,6,-9); + + my $trimmed = $content; + $trimmed =~ s/^\s+//s; + $trimmed =~ s/\s+$//s; + + $template = str_replace($block,$trimmed,$template); + + $offset = $begin+length($trimmed); + } + else { + last; + } + } + + $self->set_template($template); +} + +# parse_condtag() +# +# Bedingungstags in einem Vorlagentext verarbeiten +# +# Parameter: 1. Tagname +# 2. Status-Code (true => Tag-Inhalt anzeigen +# false => Tag-Inhalt nicht anzeigen +# +# Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + +sub parse_condtag($$) { + my ($self,$condtag,$state) = @_; + + my $template = $self->get_template; + + while(index($template,'<'.$condtag.'>') >= 0) { + my $start = index($template,'<'.$condtag.'>'); # Beginn des Blocks + my $end = index($template,'')+length($condtag)+3; # Ende des Blocks + + my $extract = substr($template,$start,$end-$start); # Kompletten Bedingungsblock extrahieren... + + my $replacement = ($state) ? substr($extract,length($condtag)+2,0-length($condtag)-3) : ''; + + $template = str_replace($extract,$replacement,$template); # Block durch neue Daten ersetzen + } + + $self->set_template($template); +} + +# parse_includes() +# +# {INCLUDE}-Anweisungen verarbeiten +# +# Parameter: -nichts- +# +# Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + +sub parse_includes { + my $self = shift; + + my $template = $self->get_template; + return if(index($template,'{INCLUDE ') == -1); + + my $offset = 0; + + my $y = 0; + + while((my $begin = index($template,'{INCLUDE ',$offset)) != -1) { + $y++; + + my $start = $begin+9; + $offset = $start; + my $long = 0; + + if(substr($template,$start,1) eq '"') { + $long = 1; + $start++; + } + + my $file = ''; + my $skip = 0; + + for(my $x=$start;$xfile_name_is_absolute($file)) { + my $dir = (File::Spec->splitpath($self->{'file'}))[1]; + $dir = '.' unless($dir); + $filepath = File::Spec->catfile($dir,$file); + } + + if(-f $filepath) { + my $inc = new Template; + $inc->read_file($filepath); + + my $end = ($long == 1) + ? $start + length($file) + 2 + : $start + length($file) + 1; + + my $pre = substr($template,0,$begin); + my $post = substr($template,$end); + + $template = $pre.$inc->get_template.$post; + $offset = length($pre)+length($inc->get_template); + + undef($inc); + } + } + } + + $self->set_template($template); +} + +# ================== +# Private Funktion +# ================== + +# explode() +# +# Eine Zeichenkette ohne regulaere Ausdruecke auftrennen +# (split() hat einen Bug, deswegen verwende ich es nicht) +# +# Parameter: 1. Trennzeichenkette +# 2. Zeichenkette, die aufgetrennt werden soll +# 3. Maximale Zahl von Teilen +# +# Rueckgabe: Aufgetrennte Zeichenkette (Array) + +sub explode($$;$) { + my ($separator,$string,$limit) = @_; + my @splitted; + + my $x = 1; + my $offset = 0; + my $sep_len = length($separator); + + while((my $pos = index($string,$separator,$offset)) >= 0 && (!$limit || $x < $limit)) { + my $part = substr($string,$offset,$pos-$offset); + push(@splitted,$part); + + $offset = $pos+$sep_len; + + $x++; + } + + push(@splitted,substr($string,$offset,length($string)-$offset)); + + return @splitted; +} + +# str_replace() +# +# Zeichenkette durch andere ersetzen +# +# Parameter: 1. Zu ersetzender Text +# 2. Ersetzender Text +# 3. Zeichenkette, in der ersetzt werden soll +# +# Rueckgabe: Bearbeitete Zeichenkette (String) + +sub str_replace($$$) { + my ($search,$replace,$subject) = @_; + $search = quotemeta($search); + + $subject =~ s/$search/$replace/gs; + + return $subject; +} + +# substr_count() +# +# Zaehlt, wie oft ein String in einem String vorkommt +# (Emulation der PHP-Funktion substr_count()) +# +# Parameter: 1. Zu durchsuchender String +# 2. Zu suchender String +# +# Rueckgabe: Anzahl der Vorkommnisse (Integer) + +sub substr_count($$) { + my ($haystack,$needle) = @_; + my $qmneedle = quotemeta($needle); + + my $count = 0; + + $count++ while($haystack =~ /$qmneedle/g); + + return $count; +} + +# it's true, baby ;-) + +1; + +# +### Ende ### \ No newline at end of file diff --git a/class.Template.php b/class.Template.php new file mode 100644 index 0000000..5b43d0b --- /dev/null +++ b/class.Template.php @@ -0,0 +1,857 @@ + +# Letzte Aenderung: 25.11.2011 +# +# Copyright (C) 2002-2011 Patrick Canterino +# +# Diese Datei kann unter den Bedingungen der "Artistic License 2.0" +# weitergegeben und / oder veraendert werden. +# Siehe: +# http://www.opensource.org/licenses/artistic-license-2.0 +# + +class Template { + var $file; + var $template; + var $original; + var $old_parsing = 0; + var $vars = array(); + var $defined_vars = array(); + var $loop_vars = array(); + + # get_template() + # + # Kompletten Vorlagentext zurueckgeben + # + # Parameter: -keine- + # + # Rueckgabe: Kompletter Vorlagentext (String) + + function get_template() { + return $this->template; + } + + # set_template() + # + # Kompletten Vorlagentext aendern + # + # Parameter: Vorlagentext + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + function set_template($text) { + $this->template = $text; + } + + # add_text() + # + # Vorlagentext ans Template-Objekt anhaengen + # + # Parameter: Vorlagentext + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + function add_text($text) { + $this->set_template($this->get_template().$text); + } + + # read_file() + # + # Einlesen einer Vorlagendatei und {INCLUDE}-Anweisungen ggf. verarbeiten + # (Text wird an bereits vorhandenen Text angehaengt) + # + # Parameter: 1. Datei zum Einlesen + # 2. Status-Code (Boolean): + # true => {INCLUDE}-Anweisungen nicht verarbeiten + # false => {INCLUDE}-Anweisungen verarbeiten (Standard) + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + function read_file($file,$not_include=0) { + $this->file = $file; + + if(filesize($file) > 0) { + $fp = fopen($file,'r'); + if(!$fp) die; + $content = fread($fp,filesize($file)); + fclose($fp); + } + else $content = ''; + + $this->add_text($content); + $this->save_state(); + + if(!$not_include) $this->parse_includes(); + } + + # set_var() + # + # Wert einer Variable setzen + # + # Parameter: 1. Name der Variable + # 2. Wert, den die Variable erhalten soll + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + function set_var($var,$content) { + $this->vars[$var] = $content; + } + + # get_var() + # + # Wert einer Variable zurueckgeben + # + # Parameter: (optional) Variablenname + # + # Rueckgabe: Wert der Variable; + # wenn die Variable nicht existiert, false; + # wenn kein Variablenname angegeben wurde, wird ein + # Array mit den Variablennamen zurueckgegeben + + function get_var($var=false) { + if($var !== false) { + if(isset($this->vars[$var])) { + return $this->vars[$var]; + } + else { + return false; + } + } + else { + return array_keys($this->vars); + } + } + + # set_vars() + # + # Komplettes Variablen-Array mit einem anderen Array ueberschreiben + # + # Parameter: Array + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + function set_vars($vars) { + $this->vars = $vars; + } + + # add_vars() + # + # Zum bestehenden Variablen-Array weitere Variablen in Form eines Arrays + # hinzufuegen + # + # Parameter: Array + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + function add_vars($vars) { + $this->vars = array_merge($this->vars,$vars); + } + + # set_loop_data() + # + # Daten fuer eine Schleife setzen + # + # Parameter: 1. Name der Schleife + # 2. Array mit den Arrays mit den Variablen fuer + # die Schleifendurchgaenge + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + function set_loop_data($loop,$data) { + $this->loop_vars[$loop] = $data; + } + + # add_loop_data() + # + # Daten fuer einen Schleifendurchgang hinzufuegen + # + # Parameter: 1. Name der Schleife + # 2. Array mit den Variablen fuer den + # Schleifendurchgang + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + function add_loop_data($loop,$data) { + if(isset($this->loop_vars[$loop]) && is_array($this->loop_vars[$loop])) { + array_push($this->loop_vars[$loop],$data); + } + else { + $this->loop_vars[$loop] = array($data); + } + } + + # parse() + # + # In der Template definierte Variablen auslesen, Variablen + # ersetzen, {IF}- und {TRIM}-Bloecke parsen + # + # Parameter: -nichts- + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + function parse() { + if($this->old_parsing) return $this->parse_old(); + + # Zuerst die Schleifen parsen + + if(is_array($this->loop_vars) && ($loops = array_keys($this->loop_vars))) { + foreach($loops as $loop) { + $this->parse_loop($loop); + } + } + + # In Template-Datei definierte Variablen auslesen + + $this->get_defined_vars(); + + # Variablen ersetzen + + if(($vars = $this->get_var()) !== false && is_array($vars)) { + $this->parse_if_blocks(); + $this->replace_vars(); + } + + # {TRIM}-Bloecke entfernen + + $this->parse_trim_blocks(); + } + + # parse_old() + # + # In der Template definierte Variablen auslesen, Variablen + # ersetzen, {IF}- und {TRIM}-Bloecke parsen + # (alte Methode) + # + # Parameter: -nichts- + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + function parse_old() { + # Zuerst die Schleifen parsen + + if(is_array($this->loop_vars) && ($loops = array_keys($this->loop_vars))) { + foreach($loops as $loop) { + $this->parse_loop($loop); + } + } + + # Normale Variablen durchgehen + + if(($vars = $this->get_var()) !== false && is_array($vars)) { + foreach($vars as $var) { + $val = $this->get_var($var); + + $this->parse_if_block($var,$val); + + if(is_array($val)) { + $this->fillin_array($var,$val); + } + else { + $this->fillin($var,$val); + } + + unset($val); + } + } + + # Jetzt dasselbe mit denen, die direkt in der Template-Datei definiert + # sind, machen. Ich weiss, dass das eine ziemlich unsaubere Loesung ist, + # aber es funktioniert + + $this->get_defined_vars(); + + foreach($this->defined_vars as $var) { + $val = $this->get_var($var); + + $this->parse_if_block($var,$val); + $this->fillin($var,$val); + + unset($val); + } + + # {TRIM}-Bloecke entfernen + + $this->parse_trim_blocks(); + } + + # fillin() + # + # Variablen durch Text ersetzen + # + # Parameter: 1. Variable zum Ersetzen + # 2. Text, durch den die Variable ersetzt werden soll + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + function fillin($var,$text) { + $template = $this->get_template(); + $template = str_replace('{'.$var.'}',$text,$template); + + $this->set_template($template); + } + + # fillin_array() + # + # Variable durch Array ersetzen + # + # Parameter: 1. Variable zum Ersetzen + # 2. Array, durch das die Variable ersetzt werden soll + # 3. Zeichenkette, mit der das Array verbunden werden soll + # (Standard: '') + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + function fillin_array($var,$array,$glue='') { + $this->fillin($var,implode($glue,$array)); + } + + # replace_vars() + # + # Variablen eine nach der anderen ersetzen. Sollte in einer Variable eine + # andere Variable auftauchen, so wird diese nicht ersetzt. + # + # Parameter: Array mit zu parsenden Variablen (optional) + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + function replace_vars($valid=array()) { + $template = $this->get_template(); + + $valid_vars = (empty($valid)) ? $this->get_var() : $valid; + + for($x=0;$xget_var($var))) { + $content = implode('',$this->get_var($var)); + } + else { + $content = $this->get_var($var); + } + + # Daten vor und nach der Variable + + $pre = substr($template,0,$x); + $post = substr($template,strlen($pre)+2+strlen($var)); + + # Alles neu zusammensetzen + + $template = $pre.$content.$post; + + # Zaehler aendern + + $x = strlen($pre.$content)-1; + } + } + } + } + + $this->set_template($template); + } + + # to_file() + # + # Template in Datei schreiben + # + # Parameter: Datei-Handle + # + # Rueckgabe: Status-Code (Boolean) + + function to_file($handle) { + return @fwrite($handle,$this->get_template()); + } + + # reset() + # + # Den gesicherten Stand des Template-Textes wiederherstellen + # + # Parameter: -nichts- + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + function reset() { + $this->template = $this->original; + } + + # save_state() + # + # Aktuellen Stand des Template-Textes sichern + # (alte Sicherung wird ueberschrieben) + # + # Parameter: -nichts- + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + function save_state() { + $this->original = $this->template; + } + + # parse_loop() + # + # Eine Schleife parsen + # + # Parameter: Name der Schleife + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + function parse_loop($name) { + $template = $this->get_template(); + if(strpos($template,'{LOOP '.$name.'}') === false) return; + + $offset = 0; + $name_len = strlen($name); + + while(($begin = strpos($template,'{LOOP '.$name.'}',$offset)) !== false) { + if(($end = strpos($template,'{ENDLOOP}',$begin+6+$name_len)) !== false) { + $block = substr($template,$begin,$end+9-$begin); + $content = substr($block,$name_len+7,-9); + + $parsed_block = ''; + + for($x=0;$xloop_vars[$name]);$x++) { + $loop_data = $this->loop_vars[$name][$x]; + $loop_vars = array_keys($loop_data); + + $ctpl = new Template; + $ctpl->set_template($content); + + foreach($loop_vars as $loop_var) { + $ctpl->set_var($name.'.'.$loop_var,$loop_data[$loop_var]); + } + + if($this->old_parsing) { + $ctpl->parse_old(); + } + else { + $ctpl->parse(); + } + + $parsed_block .= $ctpl->get_template(); + + unset($ctpl); + } + + $template = str_replace($block,$parsed_block,$template); + $offset = $begin+strlen($parsed_block); + } + else break; + } + + $this->set_template($template); + } + + # get_defined_vars() + # + # In der Template-Datei definierte Variablen auslesen + # + # Parameter: -nichts- + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + function get_defined_vars() { + $template = $this->get_template(); + if(strpos($template,'{DEFINE ') === false) return; + + $offset = 0; + + while(strpos($template,'{DEFINE ',$offset) !== false) { + $begin = strpos($template,'{DEFINE ',$offset)+8; + $offset = $begin; + + $name = ''; + $content = ''; + + $var_open = 0; + $name_found = 0; + $define_block = 0; + + for($x=$begin;$xget_var($name) === false) { + # Die Variable wird nur gesetzt, wenn sie nicht bereits gesetzt ist + + $this->set_var($name,$content); + array_push($this->defined_vars,$name); + } + + # {DEFINE}-Block entfernen + + $pre = substr($template,0,$begin-8); + $post = substr($template,$x+2); + + $template = $pre.$post; + + # Fertig! + + $offset = strlen($pre); + break; + } + } + elseif($template[$x] == '\\') { + # Ein Backslash wurde gefunden, er dient zum Escapen von Zeichen + + if($template[$x+1] == 'n') { + # "\n" in Zeilenumbrueche umwandeln + + $content .= "\n"; + } + else $content .= $template[$x+1]; + + $x++; + } + else $content .= $template[$x]; + } + else { + if($name_found == 1) { + if($var_open == 0) { + if($template[$x] == '"') $var_open = 1; + else break; + } + } + else { + # Variablennamen auslesen + + if($template[$x] == '}' && $name != '') { + # Wir haben einen {DEFINE}-Block + + $name_found = 1; + $define_block = 1; + + # Alles ab hier sollte mit dem Teil verbunden werden, der das + # {DEFINE} in einer Zeile verarbeitet + + # Der Parser fuer {DEFINE}-Bloecke ist nicht rekursiv, was auch + # nicht noetig sein sollte + + if(($end = strpos($template,'{ENDDEFINE}',$x)) !== false) { + $x++; + + $content = substr($template,$x,$end-$x); + + if($this->get_var($name) === false) { + # Die Variable wird nur gesetzt, wenn sie nicht bereits gesetzt ist + + $this->set_var($name,$content); + array_push($this->defined_vars,$name); + } + + $pre = substr($template,0,$begin-8); + $post = substr($template,$end+11); + + $template = $pre.$post; + + # Fertig! + + $offset = strlen($pre); + break; + } + else break; + } + elseif($template[$x] != ' ') { + $name .= $template[$x]; + } + elseif($name != '') { + $name_found = 1; + } + else break; + } + } + } + } + + $this->set_template($template); + } + + # parse_if_block() + # + # IF-Bloecke verarbeiten + # + # Parameter: 1. Name des IF-Blocks (das, was nach dem IF steht) + # 2. Status-Code (true => Inhalt anzeigen + # false => Inhalt nicht anzeigen + # 3. true => Verneinten Block nicht parsen + # false => Verneinten Block parsen (Standard) + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + function parse_if_block($name,$state,$no_negate=0) { + $template = $this->get_template(); + + $count = 0; + + while(strpos($template,'{IF '.$name.'}') !== false) { + # Das alles hier ist nicht wirklich elegant geloest... + # ... aber solange es funktioniert... ;-) + + $count++; + + $start = strpos($template,'{IF '.$name.'}'); + $tpl_tmp = substr($template,$start); + $splitted = explode('{ENDIF}',$tpl_tmp); + + $block = ''; # Kompletter bedingter Block + $ifs = 0; # IF-Zaehler (wird fuer jedes IF erhoeht und fuer jedes ENDIF erniedrigt) + + # {IF} + + for($x=0;$xfile.'"'); + + $ifs += substr_count($splitted[$x],'{IF '); # Zum Zaehler jedes Vorkommen von IF hinzuzaehlen + $ifs--; # Zaehler um 1 erniedrigen + $block .= $splitted[$x].'{ENDIF}'; # Daten zum Block hinzufuegen + + if($ifs == 0) { + # Zaehler wieder 0, also haben wir das Ende des IF-Blocks gefunden :-)) + + break; + } + } + + $if_block = substr($block,strlen($name)+5,-7); # Alles zwischen {IF} und {ENDIF} + + # {ELSE} + + $else_block = ''; # Alles ab {ELSE} + $ifs = 0; # IF-Zaehler + + $splitted = explode('{ELSE}',$if_block); + + for($x=0;$xset_template($template); + + # Evtl. verneinte Form parsen + + if(!$no_negate) { + $this->parse_if_block('!'.$name,!$state,1); + } + } + + # parse_if_blocks() + # + # IF-Bloecke zu allen definierten Variablen verarbeiten + # + # Parameter: Array mit zu verarbeitenden IF-Bloecken (optional) + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + function parse_if_blocks($valid=array()) { + $valid_vars = (empty($valid)) ? $this->get_var() : $valid; + + foreach($valid_vars as $valid_var) { + $this->parse_if_block($valid_var,$this->get_var($valid_var)); + } + } + + # parse_trim_blocks() + # + # {TRIM}-Bloecke parsen + # + # Dieser Parser ist nicht rekursiv, was auch nicht + # noetig sein sollte. + # + # Parameter: -nichts- + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + function parse_trim_blocks() { + $template = $this->get_template(); + if(strpos($template,'{TRIM}') === false) return; + + $offset = 0; + + while(($begin = strpos($template,'{TRIM}',$offset)) !== false) { + if(($end = strpos($template,'{ENDTRIM}',$begin+6)) !== false) { + $block = substr($template,$begin,$end+9-$begin); + $content = substr($block,6,-9); + + $trimmed = trim($content); + + $template = str_replace($block,$trimmed,$template); + + $offset = $begin+strlen($trimmed); + } + else break; + } + + $this->set_template($template); + } + + # parse_condtag() + # + # Bedingungstags in einem Vorlagentext verarbeiten + # + # Parameter: 1. Tagname + # 2. Status-Code (true => Tag-Inhalt anzeigen + # false => Tag-Inhalt nicht anzeigen + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + function parse_condtag($condtag,$state) { + $template = $this->get_template(); + + while(strpos($template,'<'.$condtag.'>') !== false) { + $start = strpos($template,'<'.$condtag.'>'); # Beginn des Blocks + $end = strpos($template,'')+strlen($condtag)+3; # Ende des Blocks + + $extract = substr($template,$start,$end-$start); # Kompletten Bedingungsblock extrahieren... + + $replacement = ($state) ? substr($extract,strlen($condtag)+2,0-strlen($condtag)-3) : ''; + + $template = str_replace($extract,$replacement,$template); # Block durch neue Daten ersetzen + } + + $this->set_template($template); + } + + # parse_includes() + # + # {INCLUDE}-Anweisungen verarbeiten + # + # Parameter: -nichts- + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + function parse_includes() { + $template = $this->get_template(); + if(strpos($template,'{INCLUDE ') === false) return; + + $offset = 0; + + $y = 0; + + while(($begin = strpos($template,'{INCLUDE ',$offset)) !== false) { + $y++; + + $start = $begin+9; + $offset = $start; + $long = 0; + + if($template[$start] == '"') { + $long = 1; + $start++; + } + + $file = ''; + $skip = 0; + + for($x=$start;$xfile)) $dir = dirname($this->file); + else $dir = '.'; + + $dir = str_replace('\\','/',$dir); + + if(!preg_match('!/+$!',$dir)) $dir .= '/'; + + $filepath = $dir.$file; + } + + if(is_file($filepath)) { + $inc = new Template; + $inc->read_file($filepath); + + $end = ($long == 1) + ? $start + strlen($file) + 2 + : $start + strlen($file) + 1; + + $pre = substr($template,0,$begin); + $post = substr($template,$end); + + $template = $pre.$inc->get_template().$post; + $offset = strlen($pre)+strlen($inc->get_template()); + + unset($inc); + } + } + } + + $this->set_template($template); + } +} + +# +### Ende ### + +?> \ No newline at end of file diff --git a/doc/aufbau.htm b/doc/aufbau.htm new file mode 100644 index 0000000..81b147e --- /dev/null +++ b/doc/aufbau.htm @@ -0,0 +1,181 @@ + + + + + +Aufbau einer Template-Datei + + + + + + +

Aufbau einer Template-Datei

+ + + +

Bemerkung

+ +

Beachten Sie bitte, dass der Template-Parser sehr streng ist! Wenn die Anweisungen nicht exakt die hier aufgeführte Syntax aufweisen, werden Sie vom Parser nicht verarbeitet.

+ +

Ich weiß, dass dies vor allem bei den Variablen-Definitionen für Übersicht sorgen würde, aber ich habe momentan echt keine Lust darauf, mich damit herumzuschlagen, den Parser toleranter zu machen.

+ +

Nach oben

+ +

Variablen

+ +

Variablen werden beim Parsen der Template-Datei durch Werte ersetzt. Die Variablen können entweder im Script oder direkt in der Template-Datei definiert werden.

+ +

Variablen sind ganz simpel aufgebaut, es ist einfach nur ein beliebiger Name, der von geschweiften Klammern umgeben ist:

+ +
+{Name}
+
+ +

Nach oben

+ +

Variablen-Definitionen

+ +

Neben der Möglichkeit, Variablen über das Script zu setzen, haben Sie auch die Möglichkeit, direkt in der Template-Datei Variablen zu definieren. Allerdings haben die Variablen, die aus dem Script stammen, Vorrang gegenüber den in der Template definierten.

+ +

Es gibt zwei Varianten, in der Template-Datei Variablen zu definieren. Die erste Variante ist eher für kürzere Texte gedacht:

+ +
+{DEFINE Name "Wert"}
+
+ +

Hierbei erhält die Variable Name den Wert Wert. Der Name der Variable darf keine Leerzeichen oder Zeilenumbrüche oder das }-Zeichen enthalten.
+Soll der Wert einen Zeilenumbruch verwenden, so müssen Sie diesen als \n angeben. Soll ein doppeltes Anführungszeichen im Wert vorkommen, so müssen Sie diesem ebenfalls einen Backslash voranstellen (\").

+ +

Die zweite Variante ist mehr für längere Werte gedacht:

+ +
+{DEFINE Name}Wert{ENDDEFINE}
+
+ +

Auch hier erhält die Variable Name den Wert Wert. Der Name darf auch hier keine Leerzeichen oder Zeilenumbrüche oder das }-Zeichen enthalten. Der Wert darf jedes Zeichen, auch Zeilenumbrüche enthalten.

+ +

Nach dem Auslesen wird jeweils der ganze {DEFINE}-Abschnitt entfernt.

+ +

Nach oben

+ +

Bedingte Abschnitte

+ +

Mit Hilfe von bedingten Abschnitten können Sie testen, ob Variablen gesetzt sind oder nicht. Es sind also nur Wahr/Unwahr-Abfragen möglich, echte Vergleiche (z.B. mit Gleich, Ungleich usw.) lassen sich leider (noch) nicht durchführen.
+Ein bedingter Abschnitt wird von einem {IF Name} (wobei Name für den Namen einer Variable steht) und von einem {ENDIF} abschlossen.

+ +
+{IF Name}Das ist ein bedingter Abschnitt!{ENDIF}
+
+ +

Es ist übrigens möglich, auch mehrere IF-Blöcke ineinander zu verschachteln.
+Weiterhin gibt es die Möglichkeit, {ELSE}-Abschnitte einzufügen. Die werden dann angezeigt, wenn die Bedingung nicht erfüllt, also false ist.

+ +
+{IF Name}Bedingung erfüllt!{ELSE}Bedingung nicht erfüllt!{ENDIF}
+
+ +

Es ist außerdem möglich, einen Block zu verneinen:

+ +
+{IF !Name}Bedingung nicht erfüllt!{ENDIF}
+
+ +

Verneinte Blöcke werden automatisch verarbeitet.

+ +

Nach oben

+ +

Schleifen

+ +

Schleifen sind Abschnitte, die mehrmals hintereinander ausgegeben werden. Dadurch können Sie darauf verzichten, für hintereinander auszugebende Abschnitte kleine Extra-Template-Dateien anzulegen.

+ +

Schleifen werden durch ein {LOOP} und dem Namen der Schleife eingeleitet und durch ein {ENDLOOP} abgeschlossen:

+ +
+{LOOP Name}
+Dies ist die Schleife mit dem Namen "Name"!
+{ENDLOOP}
+
+ +

Sie haben nun die Möglichkeit, für jeden Schleifendurchgang einen Satz Variablen zu definieren (oder auch für alle auf einmal), bei denen man natürlich auch prüfen kann, ob sie gesetzt sind. Variablen für die Schleife sind etwas anders aufgebaut. Sie beginnen mit dem Namen der Schleife, dann kommt ein Punkt und dann der eigentliche Name der Variable. Dadurch gelten die Variablen wirklich nur für die Schleife.

+ +
+{LOOP Test}
+{IF Test.Variable}
+Für diesen Schleifendurchgang wurde die Variable "Variable" gesetzt! Sie hat den Inhalt {Test.Variable}.
+{ELSE}
+Die Variable "Variable" wurde nicht gesetzt.
+{ENDIF}
+{ENDLOOP}
+
+ +

Vorsicht: Es ist derzeit noch nicht möglich, Schleifen ineinander zu verschachteln, d.h. in einer Schleife darf sich keine weitere Schleife befinden.

+ +

Nach oben

+ +

Includes

+ +

Mit Hilfe von {INCLUDE}-Anweisungen können Sie den Inhalt einer anderen Datei in die Template-Datei einfügen. Das ist zum Beispiel für immer wiederkehrende Abschnitte sinnvoll, beispielsweise Kopf und Fuß einer HTML-Datei.

+ +

Um den Inhalt einer anderen Datei in die Template-Datei in die Template einzufügen, geben Sie einfach an der entsprechenden Stelle diese Anweisung an:

+ +
+{INCLUDE Dateiname}
+
+ +

Wenn der Dateiname Leerzeichen oder das }-Zeichen enthält, so müssen Sie den Dateinamen in doppelte Anführungszeichen setzen:

+ +
+{INCLUDE "Andere Datei"}
+
+ +

Wenn Sie einen relativen Dateipfad angeben, so gilt dieser relativ zur Template-Datei. In älteren Versionen der Template-Klasse (Versionsnummer kleiner als 2.0) waren relative Pfade relativ zum Script.

+ +

Wenn sich in der einzubindenden Datei ebenfalls {INCLUDE}-Anweisungen befinden, so werden diese ebenfalls verarbeitet.

+ +

Nach oben

+ +

{TRIM}-Blöcke

+ +

Sie können bestimmte Abschnitte in {TRIM}...{ENDTRIM}-Blöcke einschließen. Beim Parsen der Template-Datei werden bei den Blöcken voran- oder nachgestellte Leerzeichen, Zeilenumbrüche (LF, CR, CRLF) und Tabulatoren entfernt, so als würde man in PHP die Funktion trim() oder in Python die String-Methode strip() auf den Block anwenden (in Perl wird das ganze mit zwei regulären Ausdrücken erreicht).

+ +

Sinnvoll können die {TRIM}-Blöcke zum Beispiel sein, wenn Sie in der Template-Datei viele Variablen definieren und nicht möchten, dass nach dem Auslesen überflüssige Leerzeichen übrigbleiben:

+ +
+{TRIM}
+{DEFINE name "Homer Simpson"}
+{DEFINE email "homer.simpson@example.org"}
+{ENDTRIM}
+
+ +

Ohne den {TRIM}-Block würden hier sinnlose Leerzeilen stehenbleiben.

+ +
+ +

Zur Übersicht

+ +
+ +

© 2002-2011 Patrick Canterino

+ + + + + + + + + + +
Homepage:http://www.patshaping.de/
E-Mail:patrick@patshaping.de
+ + \ No newline at end of file diff --git a/doc/changes.htm b/doc/changes.htm new file mode 100644 index 0000000..87dfacb --- /dev/null +++ b/doc/changes.htm @@ -0,0 +1,206 @@ + + + + + +Versionshistorie + + + + + +

Versionshistorie

+ +

Neu in Version 2.5 (vom 27.11.2011)

+ +
    +
  • Variablen werden komplett anders ersetzt:
    +Der Vorgang des Ersetzens der Variablen wurde komplett geändert. Die Template-Klasse durchsucht den Template-Text nun Zeichen für Zeichen und ersetzt Variablen durch Text. Der Sinn hinter ist, dass auf diese Weise keine Variablen in Variablen mehr ersetzt werden können.
    +Dieses neue Verfahren ist deaktivierbar, d.h. man kann bei Problemen auf das alte Verfahren, das einfach nur Zeichenketten ersetzt, zurückgreifen.
  • +
  • set_vars() und add_vars():
    +Mit den neuen Methoden set_vars() und add_vars() ist es nun möglich, die interne Variablenliste komplett zu überschreiben oder mit mehreren Variablen und Werten auf einmal zu ergänzen.
  • +
  • {TRIM}-Blöcke in der Perl-Version funktionieren jetzt:
    +Das Verarbeiten der {TRIM}-Blöcke hat in der Perl-Version nicht funktioniert, da eine falsche Variable verwendet wurde. Dieser Fehler wurde behoben.
  • +
  • Anderer Programmierstil:
    +Der Programmierstil wurde geändert. Dies betrifft vor allem die Einrückungen.
  • +
  • Dokumentation korrigiert:
    +In der Dokumentation war die Beschreibung für die reset()- und die save_state()-Methode unvollständig.
  • +
  • Neue Lizenz:
    +Die Template-Klasse ist nun unter den Bedingungen der Artistic License 2.0 lizenziert.
  • +
+ +

Neu in Version 2.0 (vom 9.8.2006)

+ +
    +
  • get_var(), set_var() und parse():
    +Um die Arbeit mit der Template-Klasse etwas zu vereinfachen, wurde ein neues Interface für die Haupt-Arbeit eingeführt. Es besteht im Wesentlichen aus den drei neuen Methoden get_var(), set_var() und parse(). +
      +
    • get_var() gibt den Wert einer Variablen zurück. Wenn kein Name angegeben wurde, gibt get_var() die Namen aller definierten Variablen zurück.
    • +
    • set_var() weist einer Variablen einen Wert zu.
    • +
    • parse() setzt die Variablen ein, verarbeitet die {IF}-Blöcke, verarbeitet die Schleifen und liest die in der Template definierten Variablen aus.
    • +
    +
  • +
  • Variablen direkt in der Template-Datei definieren:
    +Man kann nun mit Hilfe der neuen {DEFINE}-Blöcke Variablen direkt in der Template-Datei definieren, so als hätte man sie mit set_var() definiert.
    +Es gibt hierbei zwei Möglichkeiten: +
      +
    1. {DEFINE Name "Wert"}:
      +Hierbei erhält die Variable "Name" den Wert "Wert". Innerhalb des Blockes dürfen keine Zeilenumbrüche vorkommen, ansonsten wird er ignoriert. Der Name der Variable darf keine Zeilenumbrüche oder Leerzeichen enthalten. Wenn der Wert ausgelesen wird, so wird \n durch einen Zeilenumbruch ersetzt.
    2. +
    3. {DEFINE Name}Wert{ENDDEFINE}:
      +Auch hier erhält die Variable "Name" den Wert "Wert". Der Name darf ebenfalls keine Zeilenumbrüche oder Leerzeichen enthalten, der Wert allerdings schon.
    4. +
    +Die direkt mit set_var() haben allerdings Vorrang gegenüber den erst über {DEFINE} definierten. Zusätzlich werden zweitere erst von parse() abgearbeitet, wenn erstere abgearbeitet wurden.
  • +
  • Schleifen:
    +Es wurde eine einfache Möglichkeit zur Realisierung von Schleifen in einer Template-Datei hinzugefügt.
    +Man kann einen Block jetzt in {LOOP}...{ENDLOOP}-Blöcke einschließen. Dieser Block bekommt einen Namen, diesem Namen werden dann über die Methoden add_loop_data() und/oder set_loop_data() Variablen zugewiesen. Der Block wird dann für jeden Durchgang mit neuen Werten ausgegeben.
    +Der Vorteil hiervon ist, dass man so für sich wiederholende Blöcke keine separate Template-Dateien erstellen muss.
    +Es ist zur Zeit leider noch nicht möglich, Schleifen zu verschachteln!
  • +
  • {TRIM}-Blöcke:
    +Man kann jetzt Textstellen in {TRIM}-Blöcke einschließen. Beim Inhalt werden vorangestellte und abschließendende Leerzeichen und Zeilenumbrüche entfernt.
  • +
  • Verhalten der {INCLUDE}-Anweisungen verändert:
    +Das Verhalten der {INCLUDE}-Anweisungen wurde in einigen Fällen geändert: +
      +
    • Wenn man bei einer {INCLUDE}-Anweisung einen relativen Pfad angibt, so gilt dieser Pfad nun relativ zur Template-Datei und nicht mehr zum Script.
      +So wollte ich das eigentlich immer haben. Das alte Verhalten war eine Notlösung, weil ich mir nicht anders zu helfen wusste...
    • +
    • Die Dateinamen, die bei einer {INCLUDE}-Anweisung angegeben werden, können nun auch Leerzeichen oder das }-Zeichen enthalten. In diesem Fall muss man den Dateinamen aber in doppelte Anführungszeichen setzen.
    • +
    +
  • +
  • Template zurücksetzen:
    +Mit Hilfe der neuen reset()-Methode können Sie den Template-Text in den Zustand zurückversetzen, den er nach dem Auslesen der Template-Datei hatte. Zusätzlich können Sie mit save_state() den aktuellen Zustand des Template-Textes sichern und diesen dann bei Bedarf eben mit reset() wiederherstellen.
  • +
  • Alias-Funktionen entfernt:
    +In der Perl- und in der PHP-Version wurden die alten Alias-Funktionen addtext(), as_string(), condtag() und readin() entfernt.
  • +
  • Kleine Korrekturen:
    +Es wurden verschiedene, unterschiedliche kleine Korrekturen durchgeführt: +
      +
    • Die Perl-Version verwendet jetzt nicht mehr split(), um eine Zeichenkette aufzuteilen. Stattdessen verwendet sie nun meine Portierung der explode()-Funktion von PHP. Die Grund hierfür ist ein Problem von split(), welches auch auf der verlinkten Seite beschrieben wird.
    • +
    • Die Python-Version verwendet jetzt die Objektmethoden des String-Datentyps anstatt der Methoden aus dem string-Modul.
    • +
    • Die Python-Version kommt jetzt vollständig ohne reguläre Ausdrücke aus.
    • +
    +
  • +
  • Dokumentation neu strukturiert:
    +Die Dokumentation wurde komplett neu strukturiert. Sie befindet sich nun im Unterverzeichnis doc und besteht aus mehreren Dateien.
  • +
+ +

Neu in Version 1.5a (vom 6.6.2005)

+ +
    +
  • PHP-Version nun ohne "Notices":
    +Die PHP-Version der Template-Klasse hat eine "Notice" erzeugt, wenn für error_reporting der Wert E_ALL eingestellt war.
  • +
  • Fehlermeldung bei komplett leerer Template-Datei:
    +Wenn die PHP-Version der Klasse eine Template-Datei mit einer Größe von 0 Bytes hätte einlesen sollen, hatte fread() eine Fehlermeldung erzeugt. Das ist nun behoben.
  • +
+ +

Neu in Version 1.5 (vom 5.5.2005)

+ +
    +
  • {IF}-Blöcke verneinen:
    +Man kann {IF}-Blöcke nun verneinen, indem man vor den Namen des Blockes ein ! stellt. Die Methode parse_if_block() verarbeitet diese Blöcke automatisch, es sei denn man setzt den neuen dritten Parameter dieser Routine auf true.
  • +
  • Fehlende {INCLUDE}-Dateien:
    +Wenn eine Datei über eine {INCLUDE}-Anweisung eingebunden werden soll und die Datei existiert nicht, so wird diese Anweisung nicht mehr aus dem Vorlagentext entfernt.
  • +
  • Python-Version:
    +Es existiert nun ebenfalls eine Python-Version der Template-Klasse. Von den Perl- und PHP-Versionen unterscheidet sie sich lediglich dadurch, dass sie nicht die Alias-Methoden bereitstellt (Methodennamen vor Version 1.2).
  • +
+ +

Neu in Version 1.4a (vom 21.3.2005)

+ +
    +
  • Mehrere {ENDIF} am Ende des Vorlagentextes:
    +Wenn der Vorlagentext mit mehr als einem {ENDIF} endete, hat der {IF}-Parser der Perl-Version diese nicht gefunden und das Script wegen eines Verschachtelungsfehlers beendet.
  • +
  • (Mal wieder) Nicht funktionierender Alias in PHP-Fassung:
    +Für die Methode add_text() existiert aus Kompatibilitätsgründen ein Alias namens addtext(). In der PHP-Version der Klasse wurden die Argumente, die addtext() übergeben wurden, nicht an add_text() weitergegeben.
  • +
+ +

Neu in Version 1.4 (vom 5.2.2005)

+ +
    +
  • Verschachtelungsfehler bei {IF}-Blöcken:
    +Bisher geriet der {IF}-Parser immer in eine Endlosschleife, wenn die {IF}-Blöcke nicht korrekt verschachtelt waren.
    +Das dürfte jetzt behoben sein. Der Parser prüft jetzt, ob intern das letzte {ENDIF} überschritten wurde. In diesem Fall wird das Script sofort mit einer Fehlermeldung beendet.
  • +
  • Suchen von {IF}-Blöcken in {IF}-Blöcken:
    +Um einen weiteren {IF}-Block in einem {IF}-Block zu erkennen, wird jetzt nicht mehr nach {IF, sondern nach {IF  gesucht.
    +Das ist zwar immer noch nicht das, was ich eigentlich will, aber es ist etwas besser als die alte Methode. Ich würde es ja gerne mit einem regulären Ausdruck lösen, der nach \{IF .+?\} oder so sucht, aber das hat nur noch mehr Probleme bereitet.
  • +
  • Einfache Anführungszeichen statt doppelter:
    +Es wurden, wo es angebracht war, alle doppelten Anführungszeichen durch einfache ersetzt. Das bringt hoffentlich einen Geschwindigkeitsgewinn.
  • +
  • Name der Template-Datei in den Objekteigenschaften:
    +Der Name der von read_file() eingelesenen Template-Datei wird jetzt in den Objekteigenschaften gespeichert.
  • +
+ +

Neu in Version 1.3 (vom 20.5.2004)

+ +
    +
  • {INCLUDE}-Anweisungen:
    +Es ist nun möglich, in einer Vorlage {INCLUDE Dateiname}-Anweisungen einzubauen. Die Anweisungen werden beim Einlesen der Vorlagen-Datei durch den Inhalt der angegebenen Datei ersetzt.
    +Das Verarbeiten der {INCLUDE}-Anweisungen lässt sich auch von Hand durchführen und das automatische Verarbeiten beim Lesen einer Datei lässt sich auch verhindern.
  • +
  • to_file():
    +Mit der neuen Methode to_file() ist es möglich, den kompletten Vorlagentext in eine zuvor geöffnete Datei zu schreiben.
  • +
  • Nicht funktionierender Alias in PHP-Fassung:
    +Für die Methode add_text() existiert aus Kompatibilitätsgründen ein Alias namens addtext(). In der PHP-Version der Klasse rief dieser Alias jedoch nicht add_text() auf, sondern die nicht existierende Methode add_template().
  • +
+ +

Neu in Version 1.2a (vom 12.9.2003)

+ +
    +
  • Fehler in substr_count():
    +Die von der Perl-Version der Klasse emulierte PHP-Funktion substr_count() enthielt einen Fehler. Wenn sich der zu suchende am Ende des zu durchsuchenden Strings befand, wurde er nicht gefunden.
    +Die richtige Methode, Strings in Strings zu zählen, wurde perlfaq4 entnommen.
  • +
+ +

Neu in Version 1.2 (vom 9.9.2003)

+ +
    +
  • Methoden umbenannt:
    +(Fast) Alle Methoden dieser Klasse haben neue, intelligentere Namen erhalten. Hier die neuen Namen im Einzelnen:
    +addtext() => add_text()
    +as_string() => get_template()
    +condtag() => parse_condtag()
    +readin() => read_file()
    +Die alten Namen lassen sich selbstverständlich weiterhin verwenden. Das könnte sich aber irgendwann ändern.
  • +
  • ELSE hinzugefügt:
    +Die IF-Syntax versteht nun auch {ELSE}-Abschnitte, die angezeigt werden, wenn die Bedingung nicht erfüllt ist.
  • +
  • Variablen durch Array ersetzen:
    +Mit der neuen Funktion fillin_array() ist es nun möglich, Variablen durch Arrays zu ersetzen.
  • +
  • get_template() und set_template():
    +Mit Hilfe der neuen Methoden get_template() und set_template() ist es viel leichter geworden, auf den in den Objekt-Eigenschaften gespeicherten Vorlagentext zuzugreifen.
  • +
  • Emuliertes substr_count() überarbeitet:
    +Die von der Perl-Fassung der Klasse emulierte PHP-Funktion substr_count() wurde ein wenig verbessert. Sie teilt zunächst die Zeichenkette mit der zu zählenden Zeichenkette auf. Anschließend zählt sie von der Anzahl der so entstandenen Array-Elemente 1 ab und gibt das Ergebnis zurück.
  • +
  • Keine reguläre Ausdrücke mehr in der PHP-Version:
    +Die PHP-Version der Klasse verwendet nun keine reguläre Ausdrücke mehr, was hoffentlich zu einer Geschwindigkeitsverbesserung führt.
  • +
+ +

Neu in Version 1.1 (vom 21.7.2003)

+ +
    +
  • Neue IF-Syntax:
    +Es wird jetzt eine viel übersichtlichere Syntax für bedingte Abschnitte verwendet. Diese Abschnitte werden mit einem {IF} eingeleitet und von einem {ENDIF} abgeschlossen.
  • +
  • CondTag am Anfang:
    +Wenn ein CondTag-Abschnitt am Anfang eines Textes war, hat die PHP-Version diesen nicht erkannt, da die 0 als false interpretiert wurde.
  • +
+ +

Neu in Version 1.0 (vom 3.6.2003)

+ +
    +
  • Erste Version:
    +Dies ist die erste Version der Template-Klasse. Sie erschien mit der Version 1.3 des Guestbook und wurde nicht offiziell zum Download angeboten.
  • +
+ +
+ +

Zur Übersicht

+ +
+ +

© 2002-2011 Patrick Canterino

+ + + + + + + + + + +
Homepage:http://www.patshaping.de/
E-Mail:patrick@patshaping.de
+ + \ No newline at end of file diff --git a/doc/index.htm b/doc/index.htm new file mode 100644 index 0000000..7dbaad5 --- /dev/null +++ b/doc/index.htm @@ -0,0 +1,38 @@ + + + + + +Dokumentation der Template-Klasse + + + + + + +

Dokumentation der Template-Klasse

+ +

+Aufbau einer Template-Datei
+Templates parsen
+Templates "von Hand" parsen
+Versionshistorie +

+ +
+ +

© 2002-2011 Patrick Canterino

+ + + + + + + + + + +
Homepage:http://www.patshaping.de/
E-Mail:patrick@patshaping.de
+ + \ No newline at end of file diff --git a/doc/parsen.htm b/doc/parsen.htm new file mode 100644 index 0000000..30cb3b3 --- /dev/null +++ b/doc/parsen.htm @@ -0,0 +1,263 @@ + + + + + +Templates parsen + + + + + + +

Templates parsen

+ + + +

Klasse laden und Template einlesen

+ +

Erstmal ist es wichtig, die Klasse in Ihre Scripts einzubinden:

+ +
+# PHP:
+
+include("class.Template.php");
+
+# Perl:
+
+use Template;
+
+# Python:
+
+import template
+
+ +

Ggf. müssen Sie andere Pfade angeben, oder in Perl zunächst mit use lib einen weiteren Pfad für Perl-Module hinzufügen. Andererseits können Sie die Klassen auch direkt in Ihre Scripts einbetten.

+ +

Nun müssen Sie ein neues Objekt der Klasse anlegen:

+ +
+# PHP / Perl:
+
+$tpl = new Template;
+
+# Python:
+
+tpl = template.Template()
+
+ +

Dadurch stellt die Variable $tpl bzw. tpl ein neues Objekt der Template-Klasse dar (wird in den nachfolgenden Beispielen auch verwendet). Über das Objekt können Sie auf die verschiedenen Methoden der Klasse zugreifen.

+ +

Das Wichtigste ist, erstmal eine Datei einzulesen. Das geschieht über die Methode read_file():

+ +
+# PHP / Perl:
+
+$tpl->read_file(Datei);
+
+# Python:
+
+tpl.read_file(Datei)
+
+ +

Dadurch wird die angegebene Datei eingelesen und die {INCLUDE}-Anweisungen verarbeitet. Der Inhalt der Datei wird anschließend in den Objekteigenschaften gespeichert.
+Es ist auch möglich, den Vorlagentext direkt einzugeben. Das können Sie mit Hilfe der Methoden set_template() und add_text() erreichen. Das einzige Argument dieser Funktionen, ist der Text, der in den Objeteigenschaften gespeichert werden soll. set_template() legt den kompletten Vorlagentext fest, add_text() hängt den Text nur an (read_file() verwendet diese Methode intern auch). {INCLUDE}-Anweisungen werden hierbei allerdings nicht verarbeitet, Sie können dies jedoch manuell durch Aufruf der Methode parse_includes() durchführen.

+ +

Nach oben

+ +

Variablen setzen

+ +

Eines der wichtigsten Merkmale von Templates ist die Tatsache, dass bestimmte Abschnitte variabel sind, d.h. hier werden Daten vom Script eingefüllt. Für diese Klasse werden die variablen Abschnitte von geschweiften Klammern umschlossen. Eine Variable kann zum Beispiel so aussehen:
+{VARIABLE}
+Um für eine Variable einen Wert festzulegen, können Sie ganz einfach die Methode set_var() verwenden:

+ +
+# PHP / Perl:
+
+$tpl->set_var(Variablenname,Wert);
+
+# Python:
+
+tpl.set_var(Variablenname,Wert)
+
+ +

Bei den Variablen wird zwischen Groß- und Kleinschreibung unterschieden. Die Variable variable ist also eine andere als VARIABLE.

+ +

Sie können als Variable auch ein Array angeben, dieses wird dann ganz einfach zusammengefügt.

+ +

Auf den Inhalt einer Variable können Sie jederzeit mit der Methode get_var() zugreifen. Wenn die Variable nicht existiert, wird false zurückgegeben. Wenn Sie beim Aufruf von get_var() überhaupt keinen Variablennamen angeben, wird ein Array mit den Namen sämtlicher definierten Variablen zurückgegeben.

+ +

Nach oben

+ +

Daten für Schleifen setzen

+ +

Bei Schleifen haben Sie die Möglichkeit, entweder für jeden Abschnitt die Daten einzeln oder alle Daten auf einmal hinzuzufügen.
+Dazu stehen Ihnen die Methoden add_loop_data() und set_loop_data() zur Verfügung (erstere fügt neue Daten hinzu, letztere setzt die Daten komplett). Beide Methoden verwenden dasselbe Schema. Als erster Parameter kommt der Name der Schleife, dann der Datensatz bzw. alle Daten. Der Datensatz besteht aus einem assoziativen Array bzw. Hash-Referenz bzw. Dictionary, bei dem die Schlüssel den Namen der Variablen und der Wert eben den Wert der Variablen darstellen. Bei set_loop_data() müssen Sie die Datensätze als ein Array bzw. Array-Referenz bzw. Liste von Datensätzen übergeben.

+ +

Beispiel für add_loop_data():

+ +
+# PHP:
+
+$tpl->add_loop_data('Test-Schleife',array('name' => 'Bart Simpson', 'email' => 'el-barto@example.org'));
+$tpl->add_loop_data('Test-Schleife',array('name' => 'Homer Simpson', 'email' => 'homer.simpson@example.org'));
+
+# Perl:
+
+$tpl->add_loop_data('Test-Schleife',{'name' => 'Bart Simpson', 'email' => 'el-barto@example.org'});
+$tpl->add_loop_data('Test-Schleife',{'name' => 'Homer Simpson', 'email' => 'homer.simpson@example.org'});
+
+# Python:
+
+tpl.add_loop_data('Test-Schleife',{'name': 'Bart Simpson', 'email': 'el-barto@example.org'})
+tpl.add_loop_data('Test-Schleife',{'name': 'Homer Simpson', 'email': 'homer.simpson@example.org'})
+
+ +

Beispiel für set_loop_data():

+ +
+# PHP:
+
+$tpl->set_loop_data('Test-Schleife',array(array('name' => 'Bart Simpson', 'email' => 'el-barto@example.org'),
+                                          array('name' => 'Homer Simpson', 'email' => 'homer.simpson@example.org')));
+
+# Perl:
+
+$tpl->set_loop_data('Test-Schleife',[{'name' => 'Bart Simpson', 'email' => 'el-barto@example.org'},
+                                     {'name' => 'Homer Simpson', 'email' => 'homer.simpson@example.org'}]);
+
+# Python:
+
+tpl.set_loop_data('Test-Schleife',[{'name': 'Bart Simpson', 'email': 'el-barto@example.org'},
+                                   {'name': 'Homer Simpson', 'email': 'homer.simpson@example.org'}])
+
+ +

Nach oben

+ +

Templates parsen

+ +

Wenn Sie alle Variablen und Schleifen-Daten gesetzt haben, ist es an der Zeit, diese Daten auch auf die Template-Datei anzuwenden. Dies geschieht mit Hilfe der Methode parse():

+ +
+# PHP / Perl:
+
+$tpl->parse();
+
+# Python:
+
+tpl.parse()
+
+ +

Dadurch werden alle Variablen durch Text ersetzt, bedingte Blöcke und Schleifen verarbeitet und in der Template-Datei definierte Variablen ausgelesen und auf die Template-Datei angewendet.

+ +

Zu guter letzt können Sie noch die verarbeiteten Daten zurückgeben lassen:

+ +
+# PHP / Perl:
+
+$template = $tpl->get_template();
+
+# Python:
+
+template = tpl.get_template()
+
+ +

Dadurch enthält die Variable $template bzw. template die nun verarbeitete Template-Datei (sie können get_template() übrigens jederzeit verwenden, um an den Vorlagentext heranzukommen).

+ +

Weiterhin können Sie den kompletten Vorlagentext auch in eine Datei schreiben. Diese muss allerdings bereits geöffnet sein. Verwenden Sie dazu die Methode to_file() und geben Sie als Parameter das Handle der geöffneten Datei an.

+ +
+# PHP:
+
+$handle = fopen("datei.htm","w");
+$tpl->to_file($handle);
+fclose($handle);
+
+# Perl:
+
+open(HANDLE,">datei.htm");
+$tpl->to_file(\*HANDLE);
+close(HANDLE);
+
+# Python:
+
+handle = open("datei.htm","w")
+tpl.to_file(handle)
+handle.close()
+
+ +

Achtung:
+Mit Version 2.5 der Template-Klasse hat sich der komplette Vorgang des Parsens verändert. Falls Sie merken, dass sich dadurch das Ergebnis des endgütigen Textes von dem, was Sie gewohnt sind, unterscheidet, können Sie wieder auf den alten Parsing-Vorgang umschalten. Fügen Sie dazu irgendwo vor dem Aufruf von parse() folgende Zeile ein:

+ +
+# PHP:
+
+$tpl->old_parsing = 1;
+
+# Perl:
+
+$tpl->{'old_parsing'} = 1;
+
+# Python:
+
+tpl.old_parsing = 1
+
+ +

Durch diese Anweisung aktivieren Sie den alten Parsing-Mechanismus. Wenn Sie zu dieser Maßnahme greifen müssen (was ich natürlich nicht hoffe), würde ich mich freuen, wenn Sie mir eine kurze Mail schicken, damit wir uns dieses Problem evtl. gemeinsam mal ansehen können.

+ +

Nach oben

+ +

Zustand sichern und wiederherstellen

+ +

Falls Sie den Template-Text wieder in den Zustand zurückversetzen möchten, den er direkt nach dem Einlesen der Template-Datei hatte, müssen Sie diese nicht wieder neu einlesen. Sie können ganz einfach die Methode reset() verwenden:

+ +
+# PHP / Perl:
+
+$tpl->reset()
+
+# Python:
+
+tpl.reset()
+
+ +

Umgekehrt können Sie den aktuellen Status des Template-Textes auch sichern, um später diesen Status wiederherstellen zu können. Dies geschieht mit der Methode save_state():

+ +
+# PHP / Perl:
+
+$tpl->save_state()
+
+# Python:
+
+tpl.save_state()
+
+ +

Dadurch können Sie diesen Status mit reset() wiederherstellen. Es ist dadurch allerdings nicht mehr möglich den Zustand, den der Template-Text direkt nach dem Einlesen hatte, wiederherzustellen.

+ +
+ +

Zur Übersicht

+ +
+ +

© 2002-2011 Patrick Canterino

+ + + + + + + + + + +
Homepage:http://www.patshaping.de/
E-Mail:patrick@patshaping.de
+ + \ No newline at end of file diff --git a/doc/style.css b/doc/style.css new file mode 100644 index 0000000..b4d460d --- /dev/null +++ b/doc/style.css @@ -0,0 +1,86 @@ +#content, #content ul +{ + list-style-type: none; + margin-left: 0cm; +} +.upanddown +{ + font-size: 8pt; + background-color: #E8E8E8; + padding: 3px; + margin-left: 0.5cm; + margin-right: 0.5cm; + white-space: nowrap; +} +a:link, a:visited, a:active, a:focus +{ + font-weight: normal; + text-decoration: none; + color: #0000FF; +} +a:link:hover, a:visited:hover, a:active:hover, a:focus:hover +{ + font-weight: normal; + text-decoration: underline; + color: #0000FF; +} +body +{ + font-family: Verdana, Tahoma, Arial, Helvetica, sans-serif; + font-size: 10pt; + color: #000000; + background-color: #FFFFFF; +} +code +{ + font-family: 'Courier New', Courier, monospace; + font-size: 10pt; + color: #0000B0; +} +h1 +{ + font-size: 18pt; + font-weight: bold; +} +h2 +{ + font-size: 13pt; + font-weight: bold; + padding-left: 0.2cm; + padding-right: 0.2cm; +} +li +{ + margin-top: 3px; +} +ol, ul +{ + padding-left: 0.5cm; + padding-right: 0.5cm; + margin-left: 1cm; +} +p +{ + padding-left: 0.5cm; + padding-right: 0.5cm; +} +pre.code +{ + font-family: 'Courier New', Courier, monospace; + font-size: 10pt; + color: #0000B0; + background-color: #FFEEEE; + margin-left: 0.5cm; + margin-right: 0.5cm; + padding: 0.3cm; +} +table +{ + font-size: 10pt; + margin-left: 0.5cm; + margin-right: 0.5cm; +} +td +{ + vertical-align: top; +} \ No newline at end of file diff --git a/doc/vonhand.htm b/doc/vonhand.htm new file mode 100644 index 0000000..67242a9 --- /dev/null +++ b/doc/vonhand.htm @@ -0,0 +1,154 @@ + + + + + +Templatates "von Hand" parsen + + + + + + +

Templatates "von Hand" parsen

+ +

Neben den herkömmlichen Methoden, die die Template-Dateien weitgehend automatisch verarbeiten, haben Sie auch die Möglichkeit, die Template-Dateien sozusagen "von Hand" zu verarbeiten. Sie haben hierbei genaue Kontrolle über die zu ersetzenden Variablen, die zu verarbeitenden {IF}-Blöcke usw.

+ +

Um eine Variable sofort durch Text zu ersetzen, können Sie die Methode fillin() verwenden:

+ +
+# PHP / Perl:
+
+$tpl->fillin(Variablenname,Wert);
+
+# Python:
+
+tpl.fillin(Variablenname,Wert)
+
+ +

Sie haben weiterhin die Möglichkeit, mit Hilfe der Methode fillin_array() eine Variable durch ein Array zu ersetzen (unter Perl können Sie eine Array-Referenz verwenden). Dabei werden die einzelnen Array-Elemente zusammengefügt. Die Syntax dieser Methode entspricht der von fillin(), Sie können als optionalen dritten Parameter die Zeichenkette angeben, mit der die Array-Elemente verbunden werden sollen (die Vorgabe ist eine leere Zeichenkette, also '').

+ +

Wenn Sie die Variablen mit set_var() definiert haben und diese im Template-Text nun nacheinander durch die definierten Werte ersetzen möchten, so wie es ein Aufruf von parse() tut, können Sie die Methode replace_vars() verwenden:

+ +
+# PHP / Perl:
+
+$tpl->replace_vars();
+
+# Python:
+
+tpl.replace_vars()
+
+ +

Optional können Sie hier noch ein Array als Parameter mitgeben, das die Variablen, die ersetzt werden sollen, einschränkt. Wird ein Array mitgegeben, werden nur die Variablen ersetzt, deren Namen sich in diesem Array befinden.

+ +

Genauso können Sie auch mit den {IF}-Blöcken verfahren:

+ +
+# PHP / Perl:
+
+$tpl->parse_if_block(Name,Bedingung);
+
+# Python:
+
+tpl.parse_if_block(Name,Bedingung)
+
+ +

Verneinte Blöcke werden automatisch verarbeitet. Wenn Sie den optionalen dritten Parameter von parse_if_block() auf true setzen, werden diese Blöcke nicht verarbeitet.

+ +

Falls Sie die Verarbeitung einer Schleife von Hand anstoßen möchten, können Sie die Methode parse_loop() verwenden:

+ +
+# PHP / Perl:
+
+$tpl->parse_loop(Name der Schleife);
+
+# Python:
+
+tpl.parse_loop(Name der Schleife)
+
+ +

Die Daten für die Schleifen werden allerdings weiterhin durch add_loop_data() und set_loop_data() eingefügt.

+ +

Um die mit Hilfe von {DEFINE}-Anweisungen definierten Variablen auszulesen, können Sie die Methode get_defined_vars() verwenden:

+ +
+# PHP / Perl:
+
+$tpl->get_defined_vars();
+
+# Python:
+
+tpl.get_defined_vars()
+
+ +

Dadurch werden die Variablen ausgelesen und in den Objekt-Eigenschaften abgespeichert, so als wären sie mit set_var() gesetzt worden. Sie Können Sie dann mit get_var() wieder auslesen. Die Namen aller Variablen, die in der Template-Datei definiert wurden, befinden sich in den Objekt-Eigenscaften im Array mit dem Namen defined_vars (unter Perl handelt es sich um eine Array-Referenz).

+ +

{INCLUDE}-Anweisungen können, wie bereits erwähnt, von parse_includes() verarbeitet werden:

+ +
+# PHP / Perl:
+
+$tpl->parse_includes();
+
+# Python:
+
+tpl.parse_includes()
+
+ +

Falls Sie die {TRIM}-Anweisungen manuell verarbeiten lassen möchten, steht die Methode parse_trim_blocks zur Verfügung:

+ +
+# PHP / Perl:
+
+$tpl->parse_trim_blocks();
+
+# Python:
+
+tpl.parse_trim_blocks()
+
+ +

Zusätzlich zu den normalen {IF}-Blöcken steht noch eine ältere Variante zur Verfügung. Diese soll eigentlich nicht mehr verwendet werden, da sie nicht soviele Möglichkeiten bietet und gerade bei HTML-Dokumenten für Unübersicht sorgen kann. Der Vollständigkeit halber führe ich sie aber trotzdem hier auf, zumal sie vielleicht nützlich sein kann, sollte der Parser für die normalen {IF}-Blöcke einen Bug aufweisen, die bei dieser alten Methode nicht auftritt.

+ +

Konkret werden bei dieser Variante bedingte Blöcke von HTML-Tags mit frei wählbaren Namen (eigentlich wohl eher XML, die ganzen Freaks werden mich jetzt ganz sicher verprügeln...) umschlossen - die Variante trägt deswegen auch den Namen "CondTag".
+Das kann zum Beispiel so aussehen:

+ +
+<Name>Das ist ein bedingter Abschnitt!</Name>
+
+ +

Auch hier ist es möglich, mehrere Blöcke ineinander zu verschachteln. Allerdings darf ein CondTag-Block nicht einen weiteren CondTag-Block mit dem selben Namen enthalten, weil die Funktion ansonsten ins Schleudern gerät.

+ +

Verarbeitet werden die Blöcke von der Funktion parse_condtag():

+ +
+# PHP / Perl:
+
+$tpl->parse_condtag(Name,Bedingung);
+
+# Python:
+
+tpl.parse_condtag(Name,Bedingung)
+
+ +
+ +

Zur Übersicht

+ +
+ +

© 2002-2011 Patrick Canterino

+ + + + + + + + + + +
Homepage:http://www.patshaping.de/
E-Mail:patrick@patshaping.de
+ + \ No newline at end of file diff --git a/license.txt b/license.txt new file mode 100644 index 0000000..a4810c5 --- /dev/null +++ b/license.txt @@ -0,0 +1,201 @@ + The Artistic License 2.0 + + Copyright (c) 2000-2006, The Perl Foundation. + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +Preamble + +This license establishes the terms under which a given free software +Package may be copied, modified, distributed, and/or redistributed. +The intent is that the Copyright Holder maintains some artistic +control over the development of that Package while still keeping the +Package available as open source and free software. + +You are always permitted to make arrangements wholly outside of this +license directly with the Copyright Holder of a given Package. If the +terms of this license do not permit the full use that you propose to +make of the Package, you should contact the Copyright Holder and seek +a different licensing arrangement. + +Definitions + + "Copyright Holder" means the individual(s) or organization(s) + named in the copyright notice for the entire Package. + + "Contributor" means any party that has contributed code or other + material to the Package, in accordance with the Copyright Holder's + procedures. + + "You" and "your" means any person who would like to copy, + distribute, or modify the Package. + + "Package" means the collection of files distributed by the + Copyright Holder, and derivatives of that collection and/or of + those files. A given Package may consist of either the Standard + Version, or a Modified Version. + + "Distribute" means providing a copy of the Package or making it + accessible to anyone else, or in the case of a company or + organization, to others outside of your company or organization. + + "Distributor Fee" means any fee that you charge for Distributing + this Package or providing support for this Package to another + party. It does not mean licensing fees. + + "Standard Version" refers to the Package if it has not been + modified, or has been modified only in ways explicitly requested + by the Copyright Holder. + + "Modified Version" means the Package, if it has been changed, and + such changes were not explicitly requested by the Copyright + Holder. + + "Original License" means this Artistic License as Distributed with + the Standard Version of the Package, in its current version or as + it may be modified by The Perl Foundation in the future. + + "Source" form means the source code, documentation source, and + configuration files for the Package. + + "Compiled" form means the compiled bytecode, object code, binary, + or any other form resulting from mechanical transformation or + translation of the Source form. + + +Permission for Use and Modification Without Distribution + +(1) You are permitted to use the Standard Version and create and use +Modified Versions for any purpose without restriction, provided that +you do not Distribute the Modified Version. + + +Permissions for Redistribution of the Standard Version + +(2) You may Distribute verbatim copies of the Source form of the +Standard Version of this Package in any medium without restriction, +either gratis or for a Distributor Fee, provided that you duplicate +all of the original copyright notices and associated disclaimers. At +your discretion, such verbatim copies may or may not include a +Compiled form of the Package. + +(3) You may apply any bug fixes, portability changes, and other +modifications made available from the Copyright Holder. The resulting +Package will still be considered the Standard Version, and as such +will be subject to the Original License. + + +Distribution of Modified Versions of the Package as Source + +(4) You may Distribute your Modified Version as Source (either gratis +or for a Distributor Fee, and with or without a Compiled form of the +Modified Version) provided that you clearly document how it differs +from the Standard Version, including, but not limited to, documenting +any non-standard features, executables, or modules, and provided that +you do at least ONE of the following: + + (a) make the Modified Version available to the Copyright Holder + of the Standard Version, under the Original License, so that the + Copyright Holder may include your modifications in the Standard + Version. + + (b) ensure that installation of your Modified Version does not + prevent the user installing or running the Standard Version. In + addition, the Modified Version must bear a name that is different + from the name of the Standard Version. + + (c) allow anyone who receives a copy of the Modified Version to + make the Source form of the Modified Version available to others + under + + (i) the Original License or + + (ii) a license that permits the licensee to freely copy, + modify and redistribute the Modified Version using the same + licensing terms that apply to the copy that the licensee + received, and requires that the Source form of the Modified + Version, and of any works derived from it, be made freely + available in that license fees are prohibited but Distributor + Fees are allowed. + + +Distribution of Compiled Forms of the Standard Version +or Modified Versions without the Source + +(5) You may Distribute Compiled forms of the Standard Version without +the Source, provided that you include complete instructions on how to +get the Source of the Standard Version. Such instructions must be +valid at the time of your distribution. If these instructions, at any +time while you are carrying out such distribution, become invalid, you +must provide new instructions on demand or cease further distribution. +If you provide valid instructions or cease distribution within thirty +days after you become aware that the instructions are invalid, then +you do not forfeit any of your rights under this license. + +(6) You may Distribute a Modified Version in Compiled form without +the Source, provided that you comply with Section 4 with respect to +the Source of the Modified Version. + + +Aggregating or Linking the Package + +(7) You may aggregate the Package (either the Standard Version or +Modified Version) with other packages and Distribute the resulting +aggregation provided that you do not charge a licensing fee for the +Package. Distributor Fees are permitted, and licensing fees for other +components in the aggregation are permitted. The terms of this license +apply to the use and Distribution of the Standard or Modified Versions +as included in the aggregation. + +(8) You are permitted to link Modified and Standard Versions with +other works, to embed the Package in a larger work of your own, or to +build stand-alone binary or bytecode versions of applications that +include the Package, and Distribute the result without restriction, +provided the result does not expose a direct interface to the Package. + + +Items That are Not Considered Part of a Modified Version + +(9) Works (including, but not limited to, modules and scripts) that +merely extend or make use of the Package, do not, by themselves, cause +the Package to be a Modified Version. In addition, such works are not +considered parts of the Package itself, and are not subject to the +terms of this license. + + +General Provisions + +(10) Any use, modification, and distribution of the Standard or +Modified Versions is governed by this Artistic License. By using, +modifying or distributing the Package, you accept this license. Do not +use, modify, or distribute the Package, if you do not accept this +license. + +(11) If your Modified Version has been derived from a Modified +Version made by someone other than you, you are nevertheless required +to ensure that your Modified Version complies with the requirements of +this license. + +(12) This license does not grant you the right to use any trademark, +service mark, tradename, or logo of the Copyright Holder. + +(13) This license includes the non-exclusive, worldwide, +free-of-charge patent license to make, have made, use, offer to sell, +sell, import and otherwise transfer the Package with respect to any +patent claims licensable by the Copyright Holder that are necessarily +infringed by the Package. If you institute patent litigation +(including a cross-claim or counterclaim) against any party alleging +that the Package constitutes direct or contributory patent +infringement, then this Artistic License to you shall terminate on the +date that such litigation is filed. + +(14) Disclaimer of Warranty: +THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS +IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL +LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..04f991b --- /dev/null +++ b/readme.txt @@ -0,0 +1,2 @@ +Die Dokumentation für die Template-Klasse finden Sie unter +doc/index.htm \ No newline at end of file diff --git a/template.py b/template.py new file mode 100644 index 0000000..05c2345 --- /dev/null +++ b/template.py @@ -0,0 +1,840 @@ + +# +# Template (Version 2.5) +# +# Klasse zum Parsen von Templates +# +# Autor: Patrick Canterino +# Letzte Aenderung: 25.11.2011 +# +# Copyright (C) 2002-2011 Patrick Canterino +# +# Diese Datei kann unter den Bedingungen der "Artistic License 2.0" +# weitergegeben und / oder veraendert werden. +# Siehe: +# http://www.opensource.org/licenses/artistic-license-2.0 +# + +import os.path +import sys + +class Template: + + # __init__() + # + # Konstruktor + # + # Parameter: -keine- + # + # Rueckgabe: -nichts- + + def __init__(self): + self.file = '' + self.template = '' + self.original = '' + self.old_parsing = 0 + self.vars = {} + self.defined_vars = [] + self.loop_vars = {} + + # get_template() + # + # Kompletten Vorlagentext zurueckgeben + # + # Parameter: -keine- + # + # Rueckgabe: Kompletter Vorlagentext (String) + + def get_template(self): + return str(self.template) + + # set_template() + # + # Kompletten Vorlagentext aendern + # + # Parameter: Vorlagentext + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + def set_template(self,template): + self.template = str(template) + + # add_text() + # + # Vorlagentext ans Template-Objekt anhaengen + # + # Parameter: Vorlagentext + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + def add_text(self,text): + self.set_template(self.get_template()+str(text)) + + # read_file() + # + # Einlesen einer Vorlagendatei und {INCLUDE}-Anweisungen ggf. verarbeiten + # (Text wird an bereits vorhandenen Text angehaengt) + # + # Parameter: 1. Datei zum Einlesen + # 2. Status-Code (Boolean): + # true => {INCLUDE}-Anweisungen nicht verarbeiten + # false => {INCLUDE}-Anweisungen verarbeiten (Standard) + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + def read_file(self,file,not_include=0): + self.file = file + + fp = open(file,'r') + content = fp.read() + fp.close() + + self.add_text(content) + self.save_state() + + if not not_include: self.parse_includes() + + # set_var() + # + # Wert einer Variable setzen + # + # Parameter: 1. Name der Variable + # 2. Wert, den die Variable erhalten soll + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + def set_var(self,var,content): + self.vars[var] = content + + # get_var() + # + # Wert einer Variable zurueckgeben + # + # Parameter: (optional) Variablenname + # + # Rueckgabe: Wert der Variable; + # wenn die Variable nicht existiert, false; + # wenn kein Variablenname angegeben wurde, wird ein + # Array mit den Variablennamen zurueckgegeben + + def get_var(self,var=None): + if var is not None: + if self.vars.has_key(var): + return self.vars[var] + else: + return None + else: + return self.vars.keys() + + # set_vars() + # + # Komplettes Variablen-Array mit einem anderen Array ueberschreiben + # + # Parameter: Array + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + def set_vars(self,vars): + self.vars = vars + + # add_vars() + # + # Zum bestehenden Variablen-Array weitere Variablen in Form eines Arrays + # hinzufuegen + # + # Parameter: Array + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + def add_vars(self,vars): + self.vars.update(vars) + + # set_loop_data() + # + # Daten fuer eine Schleife setzen + # + # Parameter: 1. Name der Schleife + # 2. Array mit den Dictionaries mit den Variablen fuer + # die Schleifendurchgaenge + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + def set_loop_data(self,loop,data): + self.loop_vars[loop] = data + + # add_loop_data() + # + # Daten fuer einen Schleifendurchgang hinzufuegen + # + # Parameter: 1. Name der Schleife + # 2. Dictionary mit den Variablen fuer den + # Schleifendurchgang + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + def add_loop_data(self,loop,data): + if self.loop_vars.has_key(loop) and type(self.loop_vars[loop]) is list: + self.loop_vars[loop].append(data) + else: + self.loop_vars[loop] = [data] + + # parse() + # + # In der Template definierte Variablen auslesen, Variablen + # ersetzen, {IF}- und {TRIM}-Bloecke parsen + # + # Parameter: -nichts- + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + def parse(self): + if self.old_parsing: return self.parse_old() + + # Zuerst die Schleifen parsen + + if self.loop_vars and self.loop_vars.keys(): + loops = self.loop_vars.keys() + + for loop in loops: + self.parse_loop(loop) + + # In Template-Datei definierte Variablen auslesen + + self.get_defined_vars() + + # Variablen ersetzen + + vars = self.get_var() + + if vars is not None and type(vars) is list: + self.parse_if_blocks() + self.replace_vars() + + # {TRIM}-Bloecke entfernen + + self.parse_trim_blocks() + + # parse_old() + # + # In der Template definierte Variablen auslesen, Variablen + # ersetzen, {IF}- und {TRIM}-Bloecke parsen + # (alte Methode) + # + # Parameter: -nichts- + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + def parse_old(self): + # Zuerst die Schleifen parsen + + if self.loop_vars and self.loop_vars.keys(): + loops = self.loop_vars.keys() + + for loop in loops: + self.parse_loop(loop) + + # Normale Variablen durchgehen + + if self.get_var(): + vars = self.get_var() + + for var in vars: + val = self.get_var(var) + + self.parse_if_block(var,val) + + if type(val) is list: + self.fillin_array(var,val) + else: + self.fillin(var,val) + + # Jetzt dasselbe mit denen, die direkt in der Template-Datei definiert + # sind, machen. Ich weiss, dass das eine ziemlich unsaubere Loesung ist, + # aber es funktioniert + + self.get_defined_vars() + + for var in self.defined_vars: + val = self.get_var(var) + + self.parse_if_block(var,val) + self.fillin(var,val) + + # {TRIM}-Bloecke entfernen + + self.parse_trim_blocks() + + # fillin() + # + # Variablen durch Text ersetzen + # + # Parameter: 1. Variable zum Ersetzen + # 2. Text, durch den die Variable ersetzt werden soll + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + def fillin(self,var,text): + if text is None: text = '' + + template = self.get_template(); + template = template.replace('{'+str(var)+'}',str(text)); + + self.set_template(template); + + # fillin_array() + # + # Variable durch Array ersetzen + # + # Parameter: 1. Variable zum Ersetzen + # 2. Array, durch das die Variable ersetzt werden soll + # 3. Zeichenkette, mit der das Array verbunden werden soll + # (Standard: '') + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + def fillin_array(self,var,array,glue=''): + self.fillin(var,str(glue).join(array)) + + # replace_vars() + # + # Variablen eine nach der anderen ersetzen. Sollte in einer Variable eine + # andere Variable auftauchen, so wird diese nicht ersetzt. + # + # Parameter: Array mit zu parsenden Variablen (optional) + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + def replace_vars(self,valid=None): + template = self.get_template() + + if valid is None: + valid_vars = self.get_var() + else: + valid_vars = valid + + x = 0 + + while x < len(template): + if template[x] == '{': + for var in valid_vars: + # Pruefen, ob hier eine gueltige Variable beginnt + + if template[x+1:x+len(var)+2] == var + '}': + if type(self.get_var(var)) is list: + content = ''.join(self.get_var(var)) + else: + # Muss es nochmal zum String machen + # Hilft gegen den "ordinal not in range(128)"-Fehler + # Habe aber keine Ahnung, welche neuen Probleme das verursachen koennte + # Bin gespannt... + content = str(self.get_var(var)) + + if content is None: content = '' + + # Daten vor und nach der Variable + + pre = template[0:x] + post = template[len(pre)+2+len(var):] + + # Alles neu zusammensetzen + + template = pre + content + post + + # Zaehler aendern + + x = len(pre + content) - 1 + + x += 1 + + self.set_template(template) + + # to_file() + # + # Template in Datei schreiben + # + # Parameter: Datei-Handle + # + # Rueckgabe: Status-Code (Boolean) + + def to_file(self,handle): + return handle.write(self.get_template()) + + # reset() + # + # Den gesicherten Stand des Template-Textes wiederherstellen + # + # Parameter: -nichts- + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + def reset(self): + self.template = self.original + + # save_state() + # + # Aktuellen Stand des Template-Textes sichern + # (alte Sicherung wird ueberschrieben) + # + # Parameter: -nichts- + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + def save_state(self): + self.original = self.template + + # parse_loop() + # + # Eine Schleife parsen + # + # Parameter: Name der Schleife + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + def parse_loop(self,name): + template = self.get_template() + if template.find('{LOOP '+name+'}') == -1: return + + offset = 0 + name_len = len(name) + + while template.find('{LOOP '+name+'}',offset) != -1: + begin = template.find('{LOOP '+name+'}',offset) + + if template.find('{ENDLOOP}',begin+6+name_len) != -1: + end = template.find('{ENDLOOP}',begin+6+name_len) + + block = template[begin:end+9] + content = block[name_len+7:-9] + + parsed_block = '' + + x = 0 + + while x < len(self.loop_vars[name]): + loop_data = self.loop_vars[name][x] + loop_vars = loop_data.keys() + + ctpl = Template() + ctpl.set_template(content) + + for loop_var in loop_vars: + ctpl.set_var(name+'.'+loop_var,loop_data[loop_var]) + + if self.old_parsing: + ctpl.parse_old() + else: + ctpl.parse() + + parsed_block += ctpl.get_template() + + del(ctpl) + x += 1 + + template = template.replace(block,parsed_block) + offset = begin+len(parsed_block) + + else: + break + + self.set_template(template) + + # get_defined_vars() + # + # In der Template-Datei definierte Variablen auslesen + # + # Parameter: -nichts- + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + def get_defined_vars(self): + template = self.get_template() + if template.find('{DEFINE ') == -1: return + + offset = 0 + + while template.find('{DEFINE ',offset) != -1: + begin = template.find('{DEFINE ',offset)+8 + offset = begin + + name = '' + content = '' + + var_open = 0 + name_found = 0 + define_block = 0 + + x = begin + + while x < len(template): + if template[x] == '\012' or template[x] == '\015': + # Wenn in einem {DEFINE}-Block ein Zeilenumbruch gefunden wird, + # brechen wir mit dem Parsen des Blockes ab + + break + + if var_open == 1: + if template[x] == '"': + # Der Inhalt der Variable ist hier zu Ende + + var_open = 0 + + if template[x+1] == '}': + # Hier ist der Block zu Ende + + if self.get_var(name) is None: + # Die Variable wird nur gesetzt, wenn sie nicht bereits gesetzt ist + + self.set_var(name,content) + self.defined_vars.append(name) + + # {DEFINE}-Block entfernen + + pre = template[0:begin-8] + post = template[x+2:] + + template = pre+post + + # Fertig! + + offset = len(pre) + break + + elif template[x] == '\\': + # Ein Backslash wurde gefunden, er dient zum Escapen von Zeichen + + if template[x+1] == 'n': + # "\n" in Zeilenumbrueche umwandeln + + content += "\n" + else: + content += template[x+1] + + x += 1 + + else: + content += template[x] + + else: + if name_found == 1: + if var_open == 0: + if template[x] == '"': + var_open = 1 + else: + break + + else: + # Variablennamen auslesen + + if template[x] == '}' and name != '': + # Wir haben einen {DEFINE}-Block + + name_found = 1 + define_found = 1 + + # Alles ab hier sollte mit dem Teil verbunden werden, der das + # {DEFINE} in einer Zeile verarbeitet + + # Der Parser fuer {DEFINE}-Bloecke ist nicht rekursiv, was auch + # nicht noetig sein sollte + + if template.find('{ENDDEFINE}',x) != -1: + end = template.find('{ENDDEFINE}',x) + x += 1 + + content = template[x:end] + + if self.get_var(name) is None: + # Die Variable wird nur gesetzt, wenn sie nicht bereits gesetzt ist + + self.set_var(name,content) + self.defined_vars.append(name) + + pre = template[0:begin-8] + post = template[end+11:] + + template = pre + post + + # Fertig! + + offset = len(pre) + break + + else: + break + + elif template[x] != ' ': + name += template[x] + + elif template[x] != '': + name_found = 1 + + else: + break + + x += 1 + + self.set_template(template) + + # parse_if_block() + # + # IF-Bloecke verarbeiten + # + # Parameter: 1. Name des IF-Blocks (das, was nach dem IF steht) + # 2. Status-Code (true => Inhalt anzeigen + # false => Inhalt nicht anzeigen + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + def parse_if_block(self,name,state,no_negate=0): + name = str(name) + template = self.get_template() + + count = 0; + + while template.find('{IF '+name+'}') >= 0: + count += 1 + + start = template.find('{IF '+name+'}') + tpl_tmp = template[start:] + splitted = tpl_tmp.split('{ENDIF}') + + block = '' # Kompletter bedingter Block + ifs = 0 # IF-Zaehler (wird fuer jedes IF erhoeht und fuer jedes ENDIF erniedrigt) + + # {IF} + + x = 0 + + while x < len(splitted): + # Verschachtelungsfehler abfangen + if x == len(splitted)-1: raise TplClassIFNestingError(self.file,name,count) + + ifs += splitted[x].count('{IF ') # Zum Zaehler jedes Vorkommen von IF hinzuzaehlen + ifs -= 1 # Zaehler um 1 erniedrigen + block += splitted[x]+'{ENDIF}' # Daten zum Block hinzufuegen + + x += 1 + + if ifs == 0: + # Zaehler wieder 0, also haben wir das Ende des IF-Blocks gefunden :-)) + break + + if_block = block[len(name)+5:-7] # Alles zwischen {IF} und {ENDIF} + + # {ELSE} + + else_block = '' # Alles ab {ELSE} + ifs = 0 # IF-Zaehler + + splitted = if_block.split('{ELSE}'); + + x = 0 + + while x < len(splitted): + ifs += splitted[x].count('{IF ') # Zum Zaehler jedes Vorkommen von IF hinzuzaehlen + ifs -= splitted[x].count('{ENDIF}') # Vom Zaehler jedes Vorkommen von ENDIF abziehen + + x += 1 + + if ifs == 0: + # Zaehler 0, also haben wir das Ende des IF-Abschnitts gefunden + + # Aus dem Rest den ELSE-Block zusammenbauen + + y = x + + while y < len(splitted): + else_block += '{ELSE}'+splitted[y] + y += 1 + + if else_block: + if_block = if_block[0:len(if_block)-len(else_block)] + else_block = else_block[6:] + + break + + if state: + replacement = if_block + else: + replacement = else_block + + template = template.replace(block,replacement) + + self.set_template(template) + + # Evtl. verneinte Form parsen + + if not no_negate: + self.parse_if_block('!'+name,not state,1) + + # parse_if_blocks() + # + # IF-Bloecke zu allen definierten Variablen verarbeiten + # + # Parameter: Array mit zu verarbeitenden IF-Bloecken (optional) + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + def parse_if_blocks(self,valid=None): + if valid is None: + valid_vars = self.get_var() + else: + valid_vars = valid + + for valid_var in valid_vars: + self.parse_if_block(valid_var,self.get_var(valid_var)) + + # parse_trim_blocks() + # + # {TRIM}-Bloecke parsen + # + # Dieser Parser ist nicht rekursiv, was auch nicht + # noetig sein sollte. + # + # Parameter: -nichts- + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + def parse_trim_blocks(self): + template = self.get_template() + if template.find('{TRIM}') == -1: return + + offset = 0 + + while template.find('{TRIM}',offset) >= 0: + begin = template.find('{TRIM}',offset) + + if template.find('{ENDTRIM}',begin+6) >= 0: + end = template.find('{ENDTRIM}',begin+6) + + block = template[begin:end+9] + content = block[6:-9] + + trimmed = content.strip() + + template = template.replace(block,trimmed) + + offset = begin+len(trimmed) + else: + break + + self.set_template(template) + + # parse_condtag() + # + # Bedingungstags in einem Vorlagentext verarbeiten + # + # Parameter: 1. Tagname + # 2. Status-Code (true => Tag-Inhalt anzeigen + # false => Tag-Inhalt nicht anzeigen + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + def parse_condtag(self,condtag,state): + condtag = str(condtag) + template = self.get_template() + + while template.find('<'+condtag+'>') >= 0: + start = template.find('<'+condtag+'>') # Beginn des Blocks + end = template.find('')+len(condtag)+3 # Ende des Blocks + + extract = template[start:end] # Kompletten Bedingungsblock extrahieren... + + if state: + replacement = extract[len(condtag)+2:0-len(condtag)-3] + else: + replacement = '' + + template = template.replace(extract,replacement) # Block durch neue Daten ersetzen + + self.set_template(template) + + # parse_includes() + # + # {INCLUDE}-Anweisungen verarbeiten + # + # Parameter: -nichts- + # + # Rueckgabe: -nichts- (Template-Objekt wird modifiziert) + + def parse_includes(self): + template = self.get_template() + if template.find('{INCLUDE ') == -1: return + + offset = 0 + + while template.find('{INCLUDE ',offset) >= 0: + begin = template.find('{INCLUDE ',offset) + + start = begin+9 + offset = start + long = 0 + + if template[start] == '"': + long = 1 + start += 1 + + file = '' + skip = 0 + + x = start + + while x < len(template): + if template[x] == '\012' or template[x] == '\015': + skip = 1 + break + elif long == 0 and template[x] == ' ': + skip = 1 + break + elif long == 1 and template[x] == '"': + if template[x+1] != '}': skip = 1 + break + elif long == 0 and template[x] == '}': + break + else: + file += template[x] + + x += 1 + + if skip == 1: continue + + if file != '': + filepath = file + + if not os.path.isabs(file): + dir = os.path.dirname(self.file) + if not dir: dir = '.' + filepath = os.path.normpath(dir+'/'+file) + + if os.path.isfile(filepath): + inc = Template() + inc.read_file(file) + + if long == 1: end = start + len(file) + 2 + else: end = start + len(file) + 1 + + pre = template[0:begin] + post = template[end:] + + template = pre+inc.get_template()+post + offset = len(pre)+len(inc.get_template()) + + del(inc) + + self.set_template(template) + +# Klasse zum Erzeugen des Fehlers bei falsch verschachtelten +# {IF}-Bloecken + +class TplClassIFNestingError: + + def __init__(self,file,name,count): + self.file = file + self.name = name + self.count = count + + def __str__(self): + return 'Nesting error found while parsing IF block "'+self.name+'" nr. '+str(self.count)+' in template file "'+self.file+'"' + +# +### Ende ### \ No newline at end of file