Erweiterung um TCL-Skripte


 ... [ xml2html-Tutorial ] ... [ << Allgemeines zur Benutzung ] ... [ Datenbanken >> ] ...    ... [ Referenz ] ... 




Übersicht: Erweiterung um TCL-Skripte

  Grundlagen eigener TCL-Skripte
  TCL in xml-Dateien
  Ein simple-Tag Beispiel
  Ein compound-Tag Beispiel



Grundlagen eigener TCL-Skripte

Das Definieren eigener Makros ermöglicht sehr flexibles und übersichtliches Arbeiten bei der Erstellung umfangreicher html-Seiten.
Der Einsatz von Makros stösst aber an seine Grenzen, wenn komplexe (Programmier-)Aufgaben, wie die Auswertung von Server Log-Dateien oder Datenbank-Zugriffe, zu bewältigen sind. Die Makros würden für diese Aufgaben sehr gross und unhandlich werden.
xml2html stellt, um diesen Schwachpunkt zu beheben, eine Programmierschnittstelle zur Verfügung , mit der auch komplexe Abläufe realisiert werden können. Über die Schnittstelle ist es möglich, eigene TCL-Routinen in die Funktionalität von xml2html zu integrieren.
Für die folgenden Erklärungen und Beispiele wird eine gewisse Grundkenntnis der Skriptsprache TCL vorausgesetzt. Sollten noch keine Erfahrungen mit TCL vorhanden sein, lohnt sich ein Blick auf diese Sammlung von Manuals, bevor die nächsten Abschnitte gelesen werden.




TCL in xml-Dateien

Der <eval-tcl>-Tag ermöglicht die Ausführung von TCL-Code innerhalb einer xml-Seite:

<eval-tcl>clock format [clock seconds] -format "%d. %m. %Y"</eval-tcl>

Der xml-Code liefert das heutige Datum: 21. 01. 2019
(funktioniert nur bei laufendem xml2html-Tool, nicht in der statischen Version)

Um eine klare Trennung von dynamischen und statischen Inhalten einer Seite zu erreichen, sollte der <eval-tcl>-Tag allerdings nur zum Testen der eigenen Routinen in xml-Seiten verwendet werden. Nach dem erfolgreichem Abscchluss der Entwicklungs- und Testphase sollte der Code in spezielle Dateien ausgelagert werden.
Die nächsten beiden Abschnitte gehen auf die dafür notwendigen Schritte näher ein und beschreiben an zwei kurzen Beispielen, worauf insbesondere zu achten ist.




Ein simple-Tag Beispiel

Der wesentliche Teil bei der Erweiterung der Funktionalität von xml2html besteht darin, eine Funktion zu implementieren und diese einem Tag zuzuweisen. Der Name der Funktion setzt sich dabei aus dem Präfix process_ und dem Namen des neuen Tags (TAGNAME) zusammen.

proc process_TAGNAME args { .... }

Durch den Aufruf von <tagname> in einer xml-Datei würde die Funktion ausgeführt und das Ergebnis der Bearbeitung an dieser Stelle ausgegeben werden.
Besonders bei der Entwicklung komplexer Routinen erweist es sich oft als hilfreich, Debug-Output zu erzeugen. Zu diesem Zweck stellt xml2html eine eigene tracing-Methode bereit, die sich in den selbst geschriebenen Routinen aufrufen lässt.
Dazu wird die zu tracende Funktion bei xml2html registriert:

trc_register { process_TAGNAME }

Der Aufruf von:

trc process_TAGNAME "some useful debugging output"

schreibt dann "some useful debugging output" nach stderr. Wurde die Seite über den Apache aufgerufen, wird die Meldung entsprechend ins Apache-Error-Logfile (/var/log/httpd/error.log) geschrieben. Nach getaner Entwicklungs- und Debuggingarbeit lässt sich der trace-output leicht per vorangestelltem Minus in der Registrierungsroutine abstellen. Der folgender Eintrag bringt trc also zum Schweigen:

trc_register { -process_TAGNAME }


Um die eben genannte Funktionalität der Programmierschnittstelle einmal zu zeigen, soll ein neuer Tag erzeugt werden, mit dem es möglich ist, verschiedene Währungen zu konvertieren. Der neue Tag soll <currency> heissen und über folgende Werte parametrisierbar sein:

<currency src="" trg="" value="">

src entspricht dabei der Ausgangswährung, trg der Zielwährung und value dem zu konvertierenden Geldbetrag.
Der TCL-Code für den <currency>-Tag:

01: trc_register process_CURRENCY
02:
03: proc process_CURRENCY args {
04:   array set params {
05:     SRC "EUR"
06:     TRG "USD"
07:     VALUE "0"
08:   }
09:   array set params $args
10:
11:   array set eur {
12:     EUR "1"
13:     USD "0.9489"
14:     BPF "0.6381"
15:     YEN "118.1800"
16:     SFR "1.4769"
17:     SKR "9.0645"
18:     NKR "7.4015"
19:   }
20:
21:   trc process_CURRENCY "Converting from $params(SRC) to $params(TRG)"
22:
23:   if {$params(SRC) == "EUR" } {
24:     set res [expr $params(VALUE)*$eur($params(TRG))]
25:   } else {
26:     set res [expr $params(VALUE)/$eur($params(SRC))*$eur($params(TRG))]
27:   }
28:   return [format "%1.2f" $res]
29: }

Zuerst wird die tracing-Routine aktiviert (Zeile 1), nach erfolgreicher Implementierung der Funktion muss nur an dieser Stelle das tracing durch ein vorangestelltes minus wieder ausgeschaltet werden.
In Zeile 3 steht der Funktionskopf mit dem Namen der Funktion. Dieser setzt sich zusammen aus dem Präfix process_ und dem Tagnamen.
Die Zeilen 4 - 9 sind für die Parameter des Tags zuständig. Erst werden die Parameter mit einem default-Wert belegt (EUR, USD, 0), Zeile 9 überschreibt diese Werte dann mit den tatsächlichen durch den Tag-Aufruf übergebenen Werten. Soll kein default-Wert für einen Parameter angegeben werden, sind leere "" zu verwenden.
Das Array eur (Zeile 11) enthält die benötigten Umrechnungskurse.
In Zeile 21 wird von der Möglichkeit des debugging gebraucht gemacht. Bei jedem Aufruf der Funktion wird der String ausgewertet und nach stderr bzw. ins Error-Logfile geschrieben.
Die Zeilen 23 bis 27 enthalten die eigentliche Umrechnung, bevor in Zeile 28 das Ergebnis zurückgegeben wird.
Der TCL-Code eines Tags sollte jeweils in einer Datei mit dem Namen des Tags und der Endung ".tcl" abgespeichert werden.
In unserem Beispiel also: currency.tcl

Um den neuen Tag in einer xml-Seite nutzen zu können, muss die Funktionalität per

<tcl source="currency.tcl">

geladen werden. Wo die TCL-Files liegen müssen, damit sie durch xml2html gefunden werden, wird im Abschnitt Verzeichnisstrukturen beschrieben.

In einer kleinen Beispiel Anwendung soll jetzt das Zusammenspiel des neuen Tags mit Get/Post-Operationen sowie CGI-Variablen demonstriert werden.




Ein compound-Tag Beispiel

Im <currency>-Beispiel haben wir die Verwendung eines simple-Tags besprochen. Jetzt soll ein compound-Tag, also ein zusammengesetzter Tag mit Start und Ende verarbeitet werden.
Der neue Tag soll diesmal <javasource> heissen und keine Parameter besitzen.

<javasource> .... </javasource>

Durch <javasource> soll es möglich sein, alle Schlüsselwörter einer Programmiersprache, in diesem Fall Java, automatisch in einer bestimmten Farbe anzuzeigen.
Der TCL-Code ist auch in diesem Beispiel relativ einfach: javasource.tcl

01: trc_register -process_JAVASOURCE
02:
03: define_compound_tag "<javasource>compound</javasource>"
04:
05: proc process_JAVASOURCE args {
06:   array set params {
07:     COMPOUND ""
08:    }
09:   array set params $args
10:
11:   set res $params(COMPOUND)
12:
13:   array set array_color {
14:     green "super strictfp native synchronized finally new this catch package throws throw transient
15:             const try default import volatile instanceof"
16:     red "case switch break for if while else do continue return goto"
17:     blue "void long byte boolean float short char double int null"
18:     orange "interface class extends private abstract implements public protected static final"
19:   }
20:
21:   foreach color [array names array_color] {
22:     foreach keyword $array_color($color) {
23:       trc process_JAVASOURCE "element: $keyword"
24:       regsub -all $keyword $res <span style="color:$color">$keyword</span> res
25:     }
26:   }
27:
28:   return "<pre>[parse_xml_text $res]</pre>"
29: }

Der wichtigste Unterschied zwischen der Verarbeitung eines simple- und eines compound-Tags besteht in der Anweisung:

define_compound_tag "<tagname>compound</tagname>"

Hierdurch wird xml2html mitgeteilt, dass zwischen dem Start- und Ende-Tag noch zu bearbeitende Element stehen. Da compound von xml2html wie ein Parameter behandelt wird, muss es auch im array params (Zeile 6 - 8) deklariert werden. Die Verarbeitung von compound ist ab jetzt analog zu allen anderen Parametern.

Das folgende Java-Code-Beispiel:

<javasource>
	public class LinkedList {

	  protected static final
	  LinkedList empty = new LinkedList(null, null);

	  protected
	  LinkedList(Object info, LinkedList next)
	  {
	    this.info = info;
	    this.next = next;
	  }
	  //--------------------
	  public boolean isEmpty()
	  {
	    return this == empty;
	  }
	  //--------------------
	  public Object at(int i)
	    throws IndexOutOfBoundsException
	  {
	    if ( i < 0 || isEmpty() )
	      throw new IndexOutOfBoundsException("illegal index");

	    return ( i == 0 ) ? hd() : next.at(i - 1);
	  }
	}
</javasource>

würde nach der Bearbeitung durch die TCL-Funktion so aussehen:

	public class LinkedList {

	  protected static final
	  LinkedList empty = new LinkedList(null, null);

	  protected
	  LinkedList(Object info, LinkedList next)
	  {
	    this.info = info;
	    this.next = next;
	  }
	  //--------------------
	  public boolean isEmpty()
	  {
	    return this == empty;
	  }
	  //--------------------
	  public Object at(int i)
	    throws IndexOutOfBoundsException
	  {
	    if ( i < 0 || isEmpty() )
	      throw new IndexOutOfBoundsException("illegal index");

	    return ( i == 0 ) ? hd() : next.at(i - 1);
	  }
	}



Mehrere Parser auf einen Text anwenden
Im <javasource>-Beispiel wurde auf den Text zwischen Start- und Endtag ein neu entwickelter Textparser (Farbgestaltung) angewendet. Oft ist es sinnvoll und gewünscht nicht nur eine, sondern mehrere verschiedene Textbearbeitungsschritte durchzuführen. Dafür steht in xml2html die block-Funktion zur Verfügung. Sie erlaubt auf einen Text mehrere Parser einfach hintereinander anzuwenden.

define_compound_tag "<newtag>compound</newtag>"

proc process_NEWTAG args {
	eval process_BLOCK $args [list PROCS {parser1 parser2 ...}]
}

In diesem Beispiel wird die Verarbeitung des <newtag> an die block-Funktion übergeben. Dabei wird der block-Funktion eine Liste von Parsern (parser1 parser2 ...) mitgegeben, die auf den zu bearbeitenden Text in der Reihenfolge von links nach rechts angewendet werden.
So ist es leicht möglich, nicht nur die Farbe bestimmter Schlüsselwörter zu verändern, sondern auch deren Schriftart oder Grösse. Es müssen dafür nur einmal die entsprechenden Parser entwickelt werden, die dann beliebig kombiniert werden können.
xml2html stellt bereits zwei wichtige Parser zur Verfügung:

  • parse_xml_text
  • special2html
Mit parse_xml_text werden alle xml-Tags im Text weiterverarbeitet, special2html ersetzt alle speziellen Zeichen, wie z.B. die spitzen Klammern (< >) in ihre entsprechenden html-Sequencen (&lt; &gt;).

Der in diesem Tutorial oft verwendete <escape-xml>-Tag ist ein gutes Beispiel für die Anwendung der block-Funktion:

define_compound_tag "<keywords>compound</keywords>"

proc process_escape-xml args {
    eval process_BLOCK $args [list PROCS {special2html}]
}

Es nutzt den special2html-Parser und ermöglicht somit die einfache Darstellung von Tagname inkl. der spitzen Klammern, da diese in ihre html-Sequenz umgewandelt werden.





 ... [ xml2html-Tutorial ] ... [ << Allgemeines zur Benutzung ] ... [ Datenbanken >> ] ... [ nach oben ] ...   ... [ Referenz ] ...