Version 20 (modified by 13 years ago) (diff) | ,
---|
XML-Workflow-Skripte auf Webservice vorbereiten
Die Skripte für den XML-Workflow sollen in mehreren Kontexten funktionieren:
- als Textfilter
- auf der Commandline: mindestens einzeln, möglichst auch in einer Unix-pipe
- mit einem in Java geschriebenen Wrapper als Webservice
Im Webservice sollen die Skripte ohne Expertenwissen verwendbar sein.
Input und Output
Input der Skripte ist eine Datei oder STDIN. Output geht nach STDOUT bzw. STDERR (bei Fehlern) für textverändernde Skripte und STDERR für informierende Skripte.
Falls zusammenfassende Skripte, die intern eine Unix-pipe verwenden, nicht direkt in einen Webservice übertragbar sind, brauchen wir einen Mechanismus, der Unix-Pipes nachbildet.
Parameter-Typen
Die Skript-Parameter sollen direkt auf den Webservice abbildbar sein. Parameter-Typen:
- ja/nein, entspricht einer Checkbox: Beispiel --verbose (dieser Parameter-Typ ist bei den XML-Workflow-Skripten selten)
- Wert aus einer festen Liste, die sich selten ändert: Beispiel --DESpecs=1.1.2
- Wert aus einer Liste von Dateinamen: Beispiel --wordlist=datei1,datei2 (die Reihenfolge der Dateien ist wichtig)
- Zusammenfassungen von Parametern in einem einzelnen Parameter: Beispiel --language=LA oder --timeperiod=RENAISSANCE oder --defaults=file, bewirkt u.a. die Vorauswahl bestimmter Wortlisten
- einzelne Regelergänzungen wie --addWordlistEntry="opꝫ = opportet", --removeWordlistEntry="opꝫ" ? (eventuell ersetzbar durch eine kurze zusätzliche Datei)
- Änderungen von Zeichenlisten, zum Beispiel --addWordseparator="/", --removeWordseparator="/" ? Ein vergleichbarer Parameter könnte auch im Anzeigesystem verwendbar sein, siehe #176.
Interaktives Arbeiten
Zusätzliche Features in den webservices:
- zufrieden? anwenden oder nicht
- interaktives Arbeiten: zum Beispiel minimale Interaktivität: diff anzeigen, einzeln durchgehen.
- Mechanismus, dass sich das System die nachträglichen Korrekturen allgemein merkt: Benutzer kann weitere Liste anlegen mit Positiv-Formen und Negativ-Formen (d.h. "nein, diese Form soll nicht verändert werden")
- Service für PND, zusätzlich zu unserer eigenen Liste?
- Ausschnitt bearbeiten wie beim Textfilter nachbilden
BBEdit 10.0
In BBEdit 10.0 gibt es eine Änderung für Textfilter: der input ist nicht mehr eine temporäre Datei, sondern kommt via STDIN. Konkret hat das wenig Auswirkungen für die Programmierung der Skripte.
In BBEdit 9.6.3 gab es das Problem, dass UTF-8-output nach STDERR von BBEdit als MacRoman interpretiert wurde und deshalb unleserlich wurde. Das Problem ist in 10.0 gelöst. Der Workaround, das Ergebnis in eine Datei zu schicken, ist daher nicht mehr nötig, deshalb werde ich ihn nicht mehr verwenden. Übergangsweise gibt es das Problem, dass man BBEdit braucht, um den XML-Workflow mit Textfiltern zu verwenden, denn Textwrangler wird den Fehler noch haben. (Alternative ist die Commandline.)
Bei BBEdit 10.0 sind Textfilter jetzt in ~/Library/Application Support/BBEdit/Text Filters
. Das alte Textfilter-Verzeichnis von BBEdit 9 wird automatisch an die neue Stelle kopiert.
BBedit 10.0 ist immer noch kein reines Cocoa, aber sie haben sich viel Mühe gegeben, dass man das praktisch nicht mehr merkt.
Getopt
Ich verwende jetzt das Perl-Modul Getopt::Long für das Einlesen der Optionen (und Pod::Usage für die Dokumentation der Optionen). Dadurch ergibt sich recht natürlich folgendes Format, das auch für Textfilter funktioniert:
perl script.pl [options] [file.xml]
bzw. [file.txt] für die ersten Skripte im XML-Workflow. Wahrscheinlich ist dieses Format auch pipe-tauglich, aber das habe ich bisher nur sehr oberflächlich getestet.
Bei den Optionen werden dadurch automatisch mehrere Formate akzeptiert, zum Beispiel
- --wordlist=datei1 --wordlist=datei2
- --wordlist=datei1,datei2
- -wordlist=datei1,datei2
- --wordl datei1,datei2
- --w datei1,datei2
Beispiel (mit Zeilenumbrüchen, um es übersichtlicher zu machen):
perl "/Users/ich/Library/Application Support/BBEdit/Text Filters/Filter_5_01_insert_reg.pl" --dir=/Pfad/zum/Repository/trunk/trunk/texts/aux --wordlist=reg-wordlist-lat.txt --wordlist=reg-wordlist-lat-hentisberi.txt --wordlist=reg-wordlist-lat-alvarus.txt --simple=reg-simple-lat.txt,reg-simple-lat-alvarus.txt Alvarus-Zeile.txt
Die Reihenfolge der Parameter ist egal. Man kann also auch nicht --dir angeben, dann ein paar Dateien, dann ein neues --dir und weitere Dateien. Innerhalb eines Parameters wie wordlist ist die Reihenfolge der Dateien wichtig.
Beim Webservice wird es eine Liste von Standard-Hilfsdateien geben. Zusätzlich muss der Benutzer die Möglichkeit haben, weitere Hilfsdateien in das System hochzuladen oder mit beliebigen URLs auch Dateien einzubinden, die nicht im System sind.
Parameter --dir besser mit / am Ende? Bisher: wenn es $dir gibt, hänge $dir/ vorne an den Dateinamen dran. Mit / könnte ich $dir einfach auf Verdacht ohne Änderungen dranhängen. Oder: Wenn $dir ungleich "" ist, aber nicht mit / endet, hänge / dran? Was ist üblich?
Input und output sind immer UTF-8. Der input wird im Skript wie bisher mit "while(<>)" ausgelesen. Das funktioniert mit STDIN und Dateinamen. Ich verwende jetzt doch nicht "input=", weil alles, was nicht eine Option ist, als Dateiname interpretiert wird. (Mehr als ein Dateiname ist eigentlich bei keinem Skript sinnvoll, aber es ist nicht verboten). Ich verwende auch kein "output=", weil die defaults STDOUT für Text und STDERR für Fehlermeldungen eigentlich gut genug sind. Umleitungen kann man dann auf der Commandline mit Unix-Mitteln machen.
Error conditions: Wenn ein Skript nach STDERR schreibt, wird die Verarbeitung des Skripts oder der pipe abgebrochen. Falls nötig, kann ich in die Fehlermeldungen auch noch Fehler-Codes hineinschreiben.
Wo nach Optionen gesucht wird
Das Skript versucht, Optionen an folgenden Stellen zu finden:
- Commandline
(nach Schritt 1 wird der Text eingelesen)
- <metadata> <parameters>: wenn nur ein Textausschnitt übergeben wird, muss das aber nicht beim Textfilter ankommen
- falls das Skript als Textfilter läuft, eine zusätzliche Datei in Filter_parameters/$name.txt. Schritt 3 ist nötig, weil man einem Textfilter keine Parameter übergeben kann. Beispiel:
Text Filters/Filter_5_01_insert_reg.pl
sucht inText Filters/Filter_parameters/Filter_5_01_insert_reg.txt
.
Ich verwende jetzt, im Gegensatz zu vorher, einen relativen Pfad, weil es sonst nicht ohne Änderungen funktioniert, nachdem man das Verzeichnis trunk/schema/scripts/workflow aus dem Repository in das Textfilter-Verzeichnis kopiert hat. Siehe workflow_tutorial, insbesondere den Abschnitt für BBEdit.
Die Dateien reg-wordlist-lat-alvarus.txt
etc. würde man dann wohl nicht mehr in trunk/texts/aux
, sondern in Filter_parameters
haben.
Unterschiedliche Parameter-Formate
Der Parameter "wordlist" heißt "reg.wordlist" in <parameters>, etc. Wenn man das nicht will, muss man auf namespaces verzichten und hoffen, dass die Skript-Parameter-Namen sich nicht beißen. Und es gibt (wenige) Parameter, die zu mehr als einem Skript gehören. Unterelemente von <parameters> finde ich übertrieben. Oder <parameters skript="Filter_insert-reg">, etc.? Dann kann man die namespaces weglassen.
Und alle Parameter in einem <parameters> ohne @skript würden sich auf alle Skripte beziehen. Außerdem könnte man den Inhalt von <parameters> ebenfalls mit Getopt::Long einlesen, um ein einheitliches Parameter-Format zu haben. Ein einzelnes Skript würde dann den Inhalt von <parameters> und <parameters script="name"> übergeben. Oder vielleicht doch kein <parameters> ohne @script, denn in Filter_parameters
gibt es auch keine Datei, die für alle Skripte gilt. Dann muss man allgemeine Parameter eben für alle relevanten Skripte wiederholen. Kein großer Aufwand.
Vorschlag also: <parameters> kann mehrfach verwendet werden, mit obligatorischem @script. Darin das gleiche Optionen-Format wie auf der Commandline, einlesen mit GetOptionsFromString
.
Commandline versus Textfilter
Ob das Skript als Textfilter als Textfilter aufgerufen wird, erkennt es daran, dass die runtime environment variable $ENV{'BB_DOC_NAME'} existiert. Das ist BBEdit-spezifisch. Für Textwrangler oder andere Editoren wäre es anders.
Wenn man bereits Parameter in <parameters> angegeben hat, werden deshalb trotzdem auch noch die Parameter aus der zusätzlichen Datei eingelesen. Der Aufruf auf der Commandline ohne Parameter
perl script.pl file.xml
wäre dann nicht identisch mit dem Aufruf als Textfilter.
Alternative wäre, zum Beispiel zu prüfen, ob in Schritt 1 und 2 irgendwelche Optionen gesetzt wurden. Dann würden beim Aufruf auf der Commandline ohne jeden Parameter wie bei der Verwendung als Textfilter die Standard-Parameter aus der zusätzlichen Datei verwendet werden, aber sobald man irgendeinen Parameter setzt, wird die zusätzliche Datei nicht mehr eingelesen. Welche Variante führt zu möglichst wenig Verwirrung?
Nachbilden der Möglichkeit, den Textfilter mit einem Ausschnitt einer Datei aufzurufen: Optionen wie "startzeile" und "endzeile" oder gar die genauen Spalten haben wir ja erstmal verschoben. Vielleicht könnte man das auch sowieso besser im Webservice-Wrapper machen. Dann muss es nicht in jedem Skript einzeln stehen. (BBEDIT übergibt übrigens runtime environment variables für Startzeile und -spalte etc. an den Textfilter. Diese Information wird jedoch zurzeit nicht verwendet.)