Die Oberfläche von o++oPS

Beispiele

Erweiterte Funktionen

Tabment-Definition

Formatierte Ausgabe

 

o++oPS Web-Interface

Examples

Additional Functions

Tabment Definition

Formatted Output

 

 

 

 

o++oPS Weboberfläche

Die o++o Weboberfläche besteht aus drei Bereichen: oben dem Programmfeld, unten dem Ausgabefeld und dazwischen dem Kommandofeld.

Programmfeld

Das Programmfeld ist eine Editorkomponente. Hier werden o++o-Programme eingegeben  und bearbeitet.

Kommandofeld

Ausführen

Die Buttons "tab", "ment", "hsq", "xml", "image", "graphic", "html", "csv" und "ocaml" führen das Programm aus dem Eingabefeld aus.
Die Checkbox "autoclear" bewirkt bei den Ausgabeformen "tab", "ment", "hsq", "xml", "csv" und "ocaml", dass die alten Ergebnisse gelöscht werden, bevor die neue Ausgabe angezeigt wird. Bei der HTML-Ausgabe wird diese Angabe ignoriert, da sowieso immer das alte Dokument durch das neue ersetzt wird.

Laden und Speichern

Die Buttons "load"/ "save", der Pfeil und das Eingabefeld dazwischen sind für das Laden und Speichern verantwortlich. "load" ermöglicht es o++o-Programme und Dateinamen einzuladen. Mit dem "save" Button kann man entweder o++o-Programme oder die Ausgabe abspeichern. Der Pfeil entscheidet dabei, ob Programm  oder Ausgabe abgespeichert wird. Durch  Anklicken des Pfeils kann man dessen Richtung ändern. Den Dateinamen muss man vor dem Abspeichern im Eingabefeld daneben eingeben.

Ausgabefeld

Hier werden die Ergebnisse von o++o-Programmen angezeigt. Bewegt man den Mauszeiger in die rechte obere Ecke wird der "show" Button angezeigt. Mit diesem kann man die Ausgabe in einem neuen Fenster öffnen.

Ein Vorschlag für das Vorgehen des o++oPS-Nutzers

  1. Falls möglich ein otto-Programm laden, das annähernd das Gewünschte leistet.
  2. Das otto-Programm modifizieren falls nötig (weitere oder andere Programmzeilen; andere Werte; andere Spaltennamen, andere Operationen)
  3. Falls kein ähnliches otto-Programm gefunden wurde: Tabellenname laden ("tab", "ment, "hsq", "xml" oder "csv")
  4. "meta" und "tab" anklicken und Spaltennamen aus der TTD an gewünschte Stelle kopieren
  5. Alle Worte der Datei oder einer Spalte extrahieren und passende Worte oder Elemente an gewünschte Stelle kopieren. Worte in einer Spalte ermitteln:
    aus datei
    gib M(SPALTE)
  6. In einem zweiten Window oder einer zweiten Tab des Browsers ottoPS noch einmal starten und geeignete Schritte 1 -5 realisieren und Programmteile, Tabellennamen, Spaltennamen oder Werte in das erste Arbeitsfeld kopieren bis das Programm gewünschte Form besitzt.
  7. Falls die Keyworte noch nicht geläufig sind, können diese in der Datei keyworte.pdf gefunden werden.

28 o++oPS-Beispiele

o++oPS ist eine Endnutzerprogrammiersprache, die Wiederholgruppen einfach verwalten kann. Sie erlaubt es, Anfragen an Tabellen und Dokumente besonders einfach zu formulieren. Da die Sprache nicht nur das Ziel hat Anfragen zu formulieren, wird sie nicht mehr ottoQueryLanguage sondern ottoProgrammierSprache (ottoProgrammingSkript) genannt. Das Projekt wurde beeinflusst von CONVERT, SQL, XML und XQuery. o++oPS unterscheidet sich von "ottoQL" nicht nur durch eine Reihe von syntaktischen Veränderungen sondern auch durch semantische.

1. Eine Wiederholgruppe

Einige der grundlegenden Befehle und Begriffe werden anhand der folgenden Tabelle ottos.tab geklärt. Die Beispiele können unter http://ottops.eu getestet werden.
M(NAME,                  GEBORENIN,   L(TAT,                                   JAHR))
  Otto der Grosse        Altsachsen(De) Zum König von Deutschland gewählt       936
                                        Die Ungarn auf dem Lechfeld geschlagen  955
                                        Erster Kaiser des Heil. Röm. Reichs     962
  Otto von Mähren        Mähren         heiratete Euphemia von Ungarn          1086
  Otto von Bismarck      Preußen(De)    mit Zuckerbrot und Peitsche-Politik    1871
                                        Emser Depesche                         1870
                                        Erster Reichskanzler von Deutschlands  1871
  Nikolaus Otto          Taunus (De)    Miterfinder des Ottomotors             1876
  Otto von Guericke      MD (De)        Erfinder der Luftpumpe                 1649
                                        Halbkugelversuch vor dem Kaiser        1654
  Otto Normalverbraucher De             erlernt Autofahren                     1960
                                        erlernt eine Programmiersprache        2020
Diese Tabelle enthält eine Menge (M) von 6 Personen und für jede Person eine Wiederholgruppe (L(TAT, JAHR))-eine Liste von (TAT, JAHR)-Paaren.

2. Metadaten

Programm 1: Gib mir die Metadaten der Tabelle ottos.tab.
aus ottos.tab
("meta" einschalten und "tab" clicken)
Das Ergebnis ist eine vollständige TTD:
TABMENT: OTTOS
OTTOS: M(NAME,GEBORENIN,L(TAT,JAHR))
NAME,GEBORENIN,TAT: TEXT
JAHR: ZAHL
TABMENT ist ein Kunstwort aus TABelle und dokuMENT. Es beschreibt den Typ der aktuellen Tabelle. TTD kürzt „Tabment Typ Definition“ ab. Wenn im Folgenden die Ergebnisse als TAB-Datei angesehen werden sollen, ist "meta" auszuschalten. Alle folgenden Beispiele bestehen aus sequentiellen Programmen. Sie beginnen mit einer Tabelle (des aus-Teils) und die Operation jeder neuen Zeile wird auf das Ergebnis der vorangehenden Zeile angewandt.

3. Beispielprogramme

3.1 „Hallo Welt“- Spielerei

Programm 2: Gib zwei Worte aus.

Hallo Welt
Das Ergebnis ist eine Liste von Wörtern (L(WORT)).

Programm 3: Gib ein Paar von zwei Worten aus.

Hallo, Welt

Das Komma trennt Komponenten von Tupeln. Ein Tupel (das Paar ist ein 2-Tupel) wird in der Regel horizontal ausgegeben und Elemente von Kollektionen (Listen, Mengen, Multimengen) in der Regel vertikal. Um Platz zu sparen werden in einfachen Situationen Kollektionen auch horizontal ausgegeben.
Programm 4: Gib einen Text mit Leerzeichen aus.
"Hallo Welt"

Programm 5: Verbinde zwei Wörter.

Hallo ^ Welt # ^: Verbindung (Konkatenation) von Texten
# leitet den Zeilenkommentar ein.
Programm 6: Gib einen Gruß mit einer Liste von Worten aus.
ext GRUSS:=<Hallo Welt>
ext = Extension; Erweiterung der leeren Tabelle um eine Spalte. Das Ergebnis sind zwei Worte.
Programm 7: Gib zwei Worte mit zwei Spaltennamen aus.
ext LIEBER:=Hallo
ext GRUSS:=Welt

Das Ergebnis ist ein Paar (2-Tupel) von einspaltigen Tabellen.
Programm 8: Gib einen Text mit einem Tag (Spaltennamen) aus.
ext GRUSS:=“Hallo Welt“
Programm 9: Sortiere eine Menge von Wörtern.
ext GRUSS:=<M:Welt Hallo>
Mengen und Multimengen werden stets sortiert; die Reihenfolge der Elemente bleibt bei Listen bestehen.

3.2 Selektion a la Google

Programm 10: Gib alle Personen, die das Wort Lechfeld enthalten.
aus ottos.tab
mit Lechfeld

3.3 Präzisierte Selektion

Programm 11: Gib mir alle Daten über die Person(en) Guericke.
aus ottos.tab
mit Guericke in NAME

Spaltennamen enthalten in o++oPS-Programmen keine Kleinbuchstaben. Enthält ein Wort einen Kleinbuchstaben so wird es als Text (String) gewertet. Soll der Text Leerzeichen enthalten, so muss er in Hochkomma geschrieben werden z.B. “Otto von Guericke“. "in": jedes Wort der linken Seite kommt in der rechten Seite vor. Klein und Großschreibung findet hierbei keine Berücksichtigung.
Programm 12: Gesucht sind alle in Deutschland Geborenen.
aus ottos.tab
mit De in GEBORENIN
Programm 13: Gesucht sind alle Nichtadligen.
aus ottos.tab
ohn Von in NAME

3.4 Umstrukturierung

Programm 14: Gesucht sind alle Taten von Otto dem Großen.
aus ottos.tab
mit “otto der Grosse“ in NAME
gib L(TAT)
Programm 15: Gib zu jedem Jahr alle Taten mit Namen.
aus ottos.tab
gib M(JAHR, L(TAT, NAME))

Mit "gib" kann beliebig umstrukturiert werden. Der Nutzer kann ein beliebiges Schema oder eine ganze TTD angeben. Die Daten werden nach Jahr sortiert. Neben Mengen (M), werden auch Multimengen (B=Bag) sortiert. Durch "M-(A1,A2,...)" und "B-(A1,A2,...)" wird nach A1,A2,.. abfallend sortiert. Bei Listen (L) verbleibt die Inputreihenfolge und mit L- wird die Reihenfolge umgekehrt.

3.5 Spalten vergessen (wegnehmen)

Programm 16: Gib alle Daten vom 19.ten Jahrhundert ohne die Spalte Jahr.
aus ottos.tab
mit JAHR >= 1800 & JAHR < 1900
weg JAHR

3.6 Aggregationen in verschiedenen Quellebenen

Programm 17: Wie viele Personen und wie viele Taten enthält die Datei ottos.tab.
aus ottos.tab
gib ANZPERS, ANZTAT ANZPERS:=cnt(NAME) ANZTAT:=cnt(TAT)

3.7 Aggregationen ohne GroupBy in mehreren Zielebenen

Programm 18: Gesucht sind die Anzahl der Personen und für jedes Jahrhundert und die Anzahl der Taten.
aus ottos.tab
ext JAHRH:=zahl(JAHR : 100) +1
gib ANZ_PERS,M(JAHRH,ANZ_TAT) ANZ_PERS:=cnt(NAME)
    ANZ_TAT:=cnt(TAT)
Durch vier Leerzeichen am Anfang einer Zeile wird diese mit der vorangehenden Zeile zu einer logischen Einheit (eine Zeile) verbunden.

3.8 Selektion ohne Having

Programm 19: Gesucht sind alle Personen mit mehr als 2 Taten.
aus ottos.tab
mit cnt(L(TAT)) > 2
Programm 20: Gesucht sind zu jedem Jahrhundert die 2 letzten Taten.
aus ottos.tab
ext JAHRH:=zahl(JAHR : 100) +1
gib M(JAHRH,B(JAHR,TAT))
mit JAHR:: pos-(JAHR) < 3

3.9 Vorwärtsrekursion

Programm 21: In wie vielen Jahren verdoppelt sich die Wirtschaftskraft bei einem Wachstum von einem Prozent.
aus <L(JAHR): 0 to 100>
rec BETRAG:= first 1. next pred(BETRAG)*1.01 at JAHR
mit BETRAG <= 2
"rec"=recursive Erweiterung;
"pred"=predecessor=Vorgänger.
Der erste Ausdruck (1.) ist der Wert des ersten Jahres (0). Der zweite Ausdruck (pred(BETRAG)*1.01) berechnet die restlichen Werte jeweils aus den Vorgängerwerten.

3.10 Unäre Zahlen

Programm 22: Vier Enkel bekommen je drei Äpfel. Wie viele Äpfel benötigt man?
aus <L(KIND): Ernst Clara Ulrike Sophia>
ext <L(APFEL): |||> at KIND # "ext"=Extension=Erweiterung
gib L(APFEL)
cnt
Neben den grundlegenden elementaren Datentypen TEXT, WORT, BOOL (2 Wahrheitswerte true und false), ZAHL (ganze Zahlen) PZAHL (Kommazahlen aber mit Punkt (.) geschrieben) gibt es noch den Datentyp BAR, der nur ein Element-den Strich (|)- enthält.
Programm 23: (3+4)*5
aus <L(X): |||> , <L(X): ||||>
ext <L(Y): |||||> at X
gib ANZ ANZ:=cnt(Y)

3.11 Gewichteter Durchschnitt

Programm 24: Gesucht ist der Durchschnitt der Noten und ein gewichteter Durchschnitt aller Noten (einschließlich Klausurnoten K1 und K2) sowie der gewichtete Durchschnitt pro Fach.
M(NAME,L(FACH,      K1?,K2?,L(NOTE))
  Paul   Mathe      1   3     1 4
         Kunst      2   2     1 3 2 1 1
                              1 4 4 1
  Emma   Mathe      1   4     3 2 4 2
# ext DUR:= avg(K1?,K2?,L(NOTE))
# ext GEWICHTETER_DUR := 0.6 * avg(K1,K2)+ 0.4 * avg(L(NOTE))
gib M(FACH, GDUR) GDUR:=avg(0.6 * avg(K1,K2)+ 0.4 * avg(L(NOTE)))
rnd 2 # alle Zahlen werden 2 Stellen nach dem Komma gerundet

Es ist klar, dass der gewichtete Durchschnitt nur korrekt ist, wenn beide Klausurnoten vorhanden sind. Solange das nicht erfüllt ist, muss sich der Nutzer mit dem einfachen Durchschnitt oder einem Durchschnitt mit einer Klausurnote zufrieden geben. Letzterer erfordert auch mindestens eine Note sowie die erste Klausurnote.

3.12 Auswertung von Bankkonten

Programm 25: Wie viel habe ich 2013 und wie viel 2014 für Elektrizität bezahlt.
aus umsatz2013.csv, XX:=umsatz2014.csv
mit Strom
gib KOSTEN13,KOSTEN14 KOSTEN13:=sum(UMSATZ2013/BETRAG)
    KOSTEN14:=sum(XX/BETRAG)

Durch das Komma im aus-Teil werden die beiden Tabellen nicht verbunden sondern nebeneinander gestellt, so dass bei Sparkassendateien folgende TTD entsteht:
TABMENT: UMSATZ2013,XX
UMSATZ2013, XX: L(....,VERWENDUNGSZWECK,..., BETRAG,...)
VERWENDUNGSZWECK,...: TEXT
BETRAG: PZAHL

3.13 Verbinden von Tabellen

Die beiden folgenden Programme beziehen sich auf 2 flache (relationale) Studententabellen der folgenden Typen:
students1.tab: M(STID, NAME, LOC?, SAL, DEPT)
exams1.tab: L(STID, COURSE, MARK)
Programm 26:Gesucht sind alle Studenten, die das Wort Algebra enthalten, mit allen ihren Prüfungen.
aus students1.tab
ext exams1.tab at DEPT
mit STUDENTS1/STID=EXAMS1/STID
weg EXAMS1/STID
mit Algebra in EXAMS1

Nach dem Entfernen der redundanten Spalte STID (weg) hat das aktuelle Tabment folgende TTD:
TABMENT: STUDENTS1
STUDENTS1: M(STID,NAME,LOC?,SAL,DEPT,EXAMS1)
EXAMS1: L(COURSE,MARK)
MARK,STID: ZAHL
COURSE,DEPT,NAME,LOCATION,SEX: TEXT
Programm 27: Gesucht sind alle Studenten, die Algebra mit 1 belegt haben, mit allen Kursen, die sie belegt haben.
aus students1.tab
ext {aus exams1.tab; mit STID=STID'; weg STID} at DEPT
mit STID: (Algebra,1) in2 EXAMS1
Nach der Erweiterung „ext“ hat das aktuelle Tabment die gleiche TTD wie die oben angegebene. Innerhalb von Unterprogrammen, die durch die Klammern „{}“ angezeigt werden, kann man sich durch „'“ auf die äußeren Spaltennamen beziehen. „in2“ ist die Elementrelation und mengentheoretische Inklusion (Teilmengen- bzw. Teilkollektionsrelation).

3.14 Generierung eines kleinen Bildes

Programm 28: Generiere Punkte der Sinusfunktion und der Ableitung im Intervall [-4,4]. Füge die X-Achse mit 7 ganzzahligen Strichen ein.
aus <L(X): -4 to 4 step 0.01>
ext SINE:= sin(X)
ext ABLEITUNG:=(sin(X+0.001)-sin(X)) : 0.001
ext Y:=0 at X
ext <L(X2): -3 to 3>
ext <L(Y2): -0.05 to 0.05 step 0.01> at X2

Das "ext", das L(X2) einführt, kann auch durch ein Komma ersetzt werden. Damit die Punkte gesetzt werden, muss man "image" anklicken.

4. Literatur

Das Tabment

Ein Tabment ist ein Kunstwort zusammengesetzt aus TABelle und dokuMENT. Es kann als eine semantische Präzisierung des XML-Dokuments angesehen werden, wobei die konkrete XML-Syntax nur eine von mehreren Darstellungsformen ist. Viele XML-Dokumente lassen sich beispielsweise sehr vorteilhaft als Tabellen darstellen. Bestimmte Tabellen kann man als Punktmengen, gegeben durch ihre Koordinaten eventuell mit einem Farbwert, interpretieren, weshalb man diese Tabmente auch grafisch darstellen kann. Das Tabment in der eingeschränkten Version als NF2-Relation (Non-First-Normal-Form-Relation) wurde zunächst in der Spezifikationssprache von Kaphengst Reichel algebraisch spezifiziert. Dann wurde der Ansatz in CAML-Light implementiert. Mit dem Aufkommen von XML wurde er verallgemeinert. Diese Verallgemeinerung wollen wir hier in OCAML-Notation (Objective CAML) vorstellen. Damit die Präzisierung übersichtlich bleibt, verzichten wir auf Verbesserungen, die „lediglich“ auf eine effizientere Implementation zielen.

1. Spezifikation des Tabmentbegriffs

Tabmente sind sehr allgemeine Objekte. Zahlen, Texte, ... ,Mengen, Multimengen und Listen sind Tabmente. Diese Objekte werden alle in einer Sorte (in einem Typ) tabment zusammengefasst. Dafür benötigen wir lediglich 4 einfache Hilfssorten: Kollektionssymbole für unterschiedliche Kollektionsarten; Namen als eine Menge von einfachen Tags (z.B. Spaltennamen), elementare Werte und Schemata, die den direkten Typ des Tabments beschreiben. Wird rekursiv auch noch jeder Name des Schemas beschrieben, so sprechen wir von einer TTD (TabmentTypDefinition) des Tabments. Für die TTD muss keine neue Sorte eingeführt werden, da sie vom Typ L(NAME,SCHEME) (L=Liste) ist. Wir führen 3 eigentliche Kollektionssymbole und ein Symbol für optionale Werte (S1) ein. S1-Kollektionen enthalten kein oder ein Element. Die Kollektionen M-, B-, L- sind nur für das Sortieren von Interesse. Die Möglichkeiten der Any-Kollektion im Rahmen von o++oPS sind bei weitem noch nicht ausgeschöpft. Ihre Elemente können verschiedene Typen besitzen. Daher ist dieser Typ insbesondere für NoSQL- Ansätze interessant.
type coll_sym =
  Set | Bag | List (* M, B, L *)
| Set_minus | Bag_minus | List_minus (* M-, B-, L- *)
| S1 (* ?: optionale Werte *)
| Any;; (* A *)
type name = string;; (* Spaltennamen, Tags *)
type big_int = Big_int.big_int
type value = (* elementare Werte)
  Bar (* | der Strich im unären Zahlensystem *)
| Int_v of big_int (* Jede Zahl ist ein Wert *)
| Float_v of float
| Bool_v of bool
| String_v of string
| Stringi_v of string;; (* bestimmte Texte sind Worte *)
type scheme =
  Empty_s (* leeres Schema *)
| Inj of name (* jeder Name ist ein Schema *)
| Coll_s of coll_sym * scheme (* Kollektionsschema *)
| Tuple_s of scheme list (* Tupelschema *)
| Alternate_s of scheme list;;(* Schema für Choice *)
type tabment =
  Empty_t (* leeres Tabment: Fehlerwert *)
| El_tab of value (* jeder Value ist ein Tabment *)
| Tuple_t of tabment list (* Tupel von Tabmenten *)
| Coll_t of (coll_sym * scheme * (tabment list))
    (* Coll_t (c,s,[t1;t2;...;tn]) ist Kollektion von n Tabmenten vom Typ s *)
| Tag0 of name * tabment
    (* Tag0(n,t): t wird in den Tag n eingeschlossen *)
| Alternate_t of (scheme list) * tabment;;
    (* Alternate_t([s1;s2;...;sn],t) t muss vom Typ s1 oder s2,... oder sn sein *)

2. Beispiele Zur Illustration der Tabmentspezifikation

t1 = El_tab(String_v “Ernst“) = <TEXT: Ernst>
   = <TEXT>Ernst</TEXT> = <TABM>Ernst</TABM>
t2 = Tag0("NAME", (El_tab(String_v “Clara“))) = <NAME: Clara>
   = <NAME>Clara</NAME>
t3 = Tag0("NAME", (El_tab(String_v “Josephine“)))
   = <NAME: Josephine>
t4 = Tuple_t [t2; t3] (eine Person)
   = << NAME, NAME::
        Clara Josephine >>
   = <NAME>Clara</NAME>
     <NAME>Josephine</NAME>
t5 = Coll_t (List, Inj“NAME“, [t2; t3] ) (zwei Personen)
   = <<L(NAME)::
         Clara
         Josephine>>
   = <<L(NAME)::
         Clara Josephine>>
   = <NAME>Clara</NAME>
     <NAME>Josephine</NAME>
t6 = Tuple_t[Coll_t((S1,Inj “A1”),[Tag0(“A1”,El_tab(Int_v 10))]);Coll_t((S1,Inj “B1”),[])]
   = <<A1?, B1? ::
       10 >>
   = <A1>10</A1>
Die Schemata der einzelnen Tabmente:
type_t (t1) = Inj “TEXT”= TEXT
type_t (t2) = type_t(t3) = Inj “NAME” = NAME
type_t (t4) = Tuple_s[(Inj “NAME”); (Inj “NAME”)] = (NAME, NAME)
type_t (t5) = L(NAME)
type_t (t6) = Tuple_s[Coll_s(S1,Inj”A1”),Coll_s(S1,Inj”B1”)] = (A1?, B1?)
Die TTD's der einzelnen Tabmente:
ttd_t (t1) = [“TABMENT“, Inj“TEXT“]
ttd_t (t2) = [“TABMENT“, Inj “NAME“; “NAME“, Inj “TEXT“]
ttd_t (t3) = ttd_t (t2)
ttd_t (t4) = [”TABMENT“,Tuple_s[(Inj “NAME”);(Inj “NAME”)];“NAME“, Inj ”TEXT“]
ttd_t (t5) = [”TABMENT“, Coll_s(List, Inj”NAME”);“NAME”,Inj”TEXT”]
ttd_t (t6) = [”TABMENT“,Tuple_s[Coll_s(S1,Inj”A1”);Coll_s(S1,Inj”B1”)]; “A1”,Inj “ZAHL”]

3. Tabmente in der Praxis

Eine flache Relation im Sinne des Relationalen Datenmodells ist ein Tabment vom Typ
   M(A1,A2,...,An).
Vom praktischen Standpunkt kann man das Mengensymbol auch durch ein Multimengen- oder Listensymbol ersetzen. Die meisten csv-Dateien sind vom gleichen Typ.
NF2-Relationen enthalten Wiederholgruppen in beliebiger Verschachtelung und sind daher vom Typ
   M(A1,A2,...,M(B1,B2,...M(C1,C2,...),M(...)),M(...)...),
wobei alle genannten Ai, Bi, Ci,... elementare Typen besitzen. Eine Datenbank ist vom Typ
   DATEI1,DATEI2,...,DATEIn,
wobei jede Datei entsprechend vom oben genannten Typ ist. Ein XML-Dokument mit DTD (Document Type Definition) ist ein Tabment. Der Unterschied zwischen Kollektion und Tupel wird in der DTD beschrieben, ist im XML-Dokument aber nicht mehr sichtbar. Daher hat der Tabmentansatz Probleme XML-Dokumente ohne DTD zu verarbeiten. Durch das allgemeine Verständnis von XML können wir Wikipediadokumente ebenfalls als Tabmente auffassen. Dadurch können in Zukunft auch anspruchsvolle Anfragen an die Wikipedia gestellt werden. Die Tabmente von o++oPS werden im Arbeitsspeicher verarbeitet. Wenn versucht wird Arbeitsspeicherplatz, mit dem durch die vielen Pointer und die redundanten Tagdaten relativ großzügig umgegangen wird, einzusparen, können wir bei der Implementation von o++oPS bereits von einer In-Memory-Datenbank sprechen.

4. Tabmentoperationen

Ein Datentyp ist nicht nur eine Menge von Elementen, sondern eine Menge mit zugehörigen Operationen. Da der Begriff des Tabments sehr allgemein gefasst ist, kann man vielfältige Operationen hierüber definieren. Einzelne Werte sind Tabmente also kann man auch die gewöhnlichen arithmetischen Operationen (+,*,...) und Textoperationen auf Tabmente verallgemeinern. Das Gleiche trifft auf Vektor- und Matrixoperationen zu. Die mengentheoretischen Operationen der Relationen Algebra (Vereinigung, Durchschnitt, Mengendifferenz) lassen sich selbstverständlich verallgemeinern. Sie haben aber im Fall von Tabmenten mit Wiederholgruppen geringe praktische Bedeutung. Die Selektion kann verallgemeinert werden. Es sind jedoch positionsselektierende Operationen definierbar und viele zusätzliche und auch spitzfindigere Bedingungen. In o++oPS wird die Projektion durch eine sehr allgemeine Umstrukturierungs-operation (gib-Klausel) und durch eine simple forget-Operation (weg-Klausel) ersetzt. Das kartesische Produkt ist aus der Menge der Operationen verschwunden, kann aber relativ leicht durch die Extension (ext) und die Umstrukturierungsoperation dargestellt werden. Durch ext werden neue (komplexe) Spalten eingeführt. Die Operationen werden in „28ottoPSBeispiele“ illustriert.

Erweiterte Funktionen in o++oPS

1 Variablen

Um Daten im Hintergrund halten zu können, kann man in o++oPS Variablen verwenden.
Die Syntax zum Speichern von Werten ist folgende:
$NAME := AUSDRUCK
Dabei ist NAME der Name der Variablen und AUSDRUCK ein beliebiger Ausdruck.
Beispiel:
$C := 1 + 2, 3
Es besteht auch die Möglichkeit das aktuelle Tabment abzuspeichern.
Die Syntax ist =: $NAME
Beispiel:
1, 2
=: $C
Zugriff auf die Variablen hat man in Ausdrücken durch den Variablennamen, der aus Großbuchstaben besteht, mit vorangestelltem Dollarzeichen.
Beispiel:
ext B1:= $C + 5
$C := $C + 1

Globale Variablen

Wie man später sieht, haben die bisherigen Variablen nur Gültigkeit innerhalb eines Bereiches. Sollen Variablen überall und auch in nachgeladenen Programmen sichtbar und veränderbar sein, so kann man globale Variablen verwenden. Globale Variablen sind durch zwei füherende Dollarzeichen gekennzeichnet.

2 Funktionen

Die Syntax zur Definition von Funktionen ist:
function NAME ($P1, $P2, ... $Pn) BLOCK
Die Parameter sind Variablen P1 bis Pn. BLOCK ist entweder ein einzelnes o++oPS-Kommando oder ein o++oPS-Programm, das zwischen begin und end steht. Beispiel:
function ADD0 ($C, $D) $C + $D

function FE ($C) begin
$C
ext $C + 23
end

Aufrufen kann man die erste Funktion beispielsweise wie folgt:
$X:=1,2
aus ADD0($X,8)

Es ist möglich auf außerhalb der Funktion definierte Variablen zuzugreifen. Änderungen an diesen Variablen und neu definierte Variablen werden nach Ausführung der Funktion aber wieder vergessen.

3 include

Mit include ist es möglich Programmcode aus anderen Dateien nachzuladen.
Die Syntax ist:
include AUSDRUCK
Der Ausdruck muss vom Typ TEXT sein und ein Dateiname sein.
Beispiel:
include "functions.otto"
Das eingefügte Programm hat Zugriff auf die außerhalb definierten Variablen. Änderungen an diesen Variablen werden aber nicht an das aufrufende Programm weitergegeben. Nur die definierten Funktionen werden an das aufrufende Programm übergeben. Auch das aktuelle Tabment wird nicht verändert. Außnahme bilden die globalen Variablen.

Formatierte Ausgabe

Die Standardform zur Darstellung der Ausgabe von Otto ist die strukturierte Tabelle. Diese kann einmal in Textform als ASCII-formatierte Tabelle oder als Tabelle in einem HTML-Dokument ausgeben werden.
Die HTML-Ausgabe erlaubt es aber auch die Daten in anderen Layouts darzustellen. Dazu benötigt sie zusätzliche Formatinformationen. Diese sind an die vielleicht schon bekannte Formatierungsspache CSS (Cascading Style Sheets) angelehnt. Um die Formatinformation der HTML-Ausgabe zugänglich zu machen, werden die Daten mit o++oPS um diese erweitert. Das Schema der Formatinformation ist L(SELECT, TYPE, L(STYLE)).
Beispiel:
ext FORMAT := &&
<<L(SELECT,     TYPE,   L(STYLE))::
    DOKUMENT    div
    L(ARTIKEL)  tabelle   ohnerahmen fett>>

Das zusätzliche Tag "FORMAT" um diese Struktur ist erlaubt aber nicht notwendig.
Die Spalte SELECT wählt aus welchen Teilen der Daten ein Format zugeordnet wird.  Dazu kann man hier einen Tagnamen angeben. Kollektion ohne eigenem Namen können hier auch über L(INNERTAG) (wie im Beispiel) angesprochen werden. Die Spalte TYPE legt grob die Darstellungsart fest. Einige mögliche Werte sind table (Tabelle), div (allgemeiner Bereich), span (inline Bereich), img (Bild) und svg (plotten). (Im HTML-Dokument spiegeln sich diese Tags auch wieder.) In der Spalte L(STYLE) werden die eigentlichen Formatierungen angegeben. Hier stehen alle CSS Eigenschaften zur Verfügung. Aus Gründen der Benutzerfreundlichkeit wurden aber auch zusätzliche Abkürzungen eingeführt. So kann man die CSS Eigenschaft "font-weight:bold" durch "fett" ersetzen.
Beispiel:
ext LIST1:= <L(A1): 1 to 3>
ext LIST2 := <L(B1): 1 to A1 step 1>
ext C:= B1 + 1
ext A2:= Tabelle ^ " " ^ text(A1)
weg A1

ext && # format
<<M(SELECT,        TYPE,       L(STYLE))::
    LIST1          div  
    LIST2          table         rotation:1 rand-unten:2em
    C                            farbe:rot >>
Die äußere Kollektion (LIST1) wird nicht wie gewöhnlich als Tabelle sondern als allgemeiner Bereich per div ausgegeben. Die A1-Elemente werden auch als "div" ausgegeben, da sich die Formate automatisch weitervererben so lange kein anderes Format angegeben wird. Die inneren Kollektionen (LIST2) werden aber als Tabellen ausgegeben da ihr "TYPE" mit "table" bestimmt wurde. Die C-Spalte wird zusätzlich rot gefärbt.

Bemerkungen zum Einsatz von div und span

Sowohl "div" und "span" definieren einen Bereich. Dabei wird beim div im Text ein neuer Block eingeführt. Das heißt, dass vor und nach dem "div" Zeilenumbrüche entstehen. Dies kann man zum Beispiel benutzen um Absätze zu gestalten. Beim "span" dagegen entstehen keine Zeilenumbrüche, es erlaubt Formatierungen im laufenden Text vorzunehmen. Dies ermöglicht zum Beispiel einzelne Wörter im laufenden Text zu formatieren.
Beispiel:
ext VORNAME:= Frank
ext NACHNAME:= Schulz
ext STRASSE:= "Waldweg 3"
ext PLZ:= 09123
ext ORT:= Eindorf
tag ADRESSE

ext && # format
<<M(SELECT,        TYPE,       L(STYLE))::
    ADRESSE        div           
    VORNAME        span
    NACHNAME       span
    PLZ            span
    ORT            span >>
Hier wird die Adresse zunächst als "div" ausgegeben. Ohne weitere Angaben würden so alle Elemente der Adresse für sich in einer eigenen Zeile ausgegeben. Vorname / Nachname und PLZ / Ort sollten aber jeweils zusammen in einer Zeile stehen. Darum werden sie hier als span ausgegeben.

Es ist auch möglich zunächst mit "span" zu beginnen. Dann würden alle Elemente der Adresse nacheinander in einer Zeile erscheinen. Macht man jedoch die Straße zum "div" entsteht vor und nach der Straße ein Zeilenumbruch und die Adresse sieht aus wie gewohnt.
<<M(SELECT,        TYPE,       L(STYLE))::
    ADRESSE        span           
    STRASSE        div>>

TYPE

In der TYPE-Spalte sind alle HTML-Tags erlaubt. Einige wichtige sind in der folgenden Übersicht aufgelistet.

TYPE
Beschreibung
table
tabelle
Darstellung als Tabelle
In der Spalte STYLE sind hier zusätzlich folgende Schlüsselwörter erlaubt:
  • rotation, roation:n
    dreht die gesamte Tabelle um 90° gegen den Uhrzeigersinn. Enthält die Tabelle innere Tabellen gibt n an bis zu welcher Tiefe die Tabellen gedreht werden. Die entstehenden Spalten können in der SELECT Spalte über den Tabellennamen-[Spaltennummer] angesprochen werden. Datenspalten haben dann den TYPE td (table data) und die Kopfspalte den TYPE th (table head)
  • ohnerahmen
    per Voreinstellung werden Tabellen mit Gitternetzlinen und Rahmen ausgegeben. Das Schlüsselwort "ohnerahmen" schaltet diese ab
  • ohnekopf
    stellt die Tabelle ohne Kopf dar
div
allgemeiner Bereich
span
inline Bereich
img
Bildausgabe: das betreffende Element sollte einen Dateinamen oder eine URL enthalten
svg
Plotten
h1
h2
h3
h4
h5
h6
Überschrift

STYLE

In der STYLE-Spalte sind alle CSS-Eigenschaften zugelassen. Außerdem gibt es einige Abkürzungen.

STYLE
Beschreibung
font-weight:bold
fett
bold
fett
font-weight:bolder
extrafett
bolder
extra fett
font-weight:lighter
duenner
duenn
dünn
font-style:italic
kursiv
italic
kursiv
fint-style:oblique
schraeg
oblique
schräg
width:[ ]
breite:[ ]
gibt die Breite eines Elementes an, z.B. nützlich bei Bildern und Tabellen
Bsp: breite:250px
height:[ ]
hoehe:[ ]
gibt die Höhe eines Elementes an
text-decoration:underline
unterstrichen
underline
unterstrichen
text-decoration:overline
ueberstrichen
overline
überstrichen
text-decoration:line-through
durchgestrichen
line-through
durchgestrichen
text-decoration:blink
blinkend
blink
blinkend
text-indent:[ ]
einzug:[ ]
Einzug
line-height:[ ]
zeilenhoehe:[ ]
Zeilenhöhe
vertical-align:[ ]
vertikale_ausrichtung:[ ]
vertikaleausrichtung:[ ]
vertikale-ausrichtung:[ ]
vertikale Ausrichtung in Verbindung mit top/oben, middle/mitte, bottom/unten, baseline/basisline, sub/tief, super/hoch
Bsp: vertikaleausrichtung:oben
text-align:[ ]
textausrichtung:[ ]
text-ausrichtung:[ ]
ausrichtung:[ ]
Textausrichtung (horizontal) in Verbindung mit left/links, right/rechts, center/zentriert, justify/block
Bsp: ausrichtung:block
font-size:[ ]
schriftgroesse:[ ]
groesse:[ ]
Schriftgröße in Verbindung mit xx-small/winzig, x-small/sehrklein, small/klein, medium/mittel, large/gross, x-large/sehrgross, xx-large/riesig
margin-left:[ ]
rand-links:[ ]
linker Rand
margin-right:[ ]
rand-rechts:[ ]
rechter Rand
margin-bottom:[ ]
rand-unten:[ ]
unterer Rand
margin-top:[ ]
rand-oben:[ ]
oberer Rand
padding-left:[ ]
abstand-links:[ ]
linker Abstand
padding-right:[ ]
abstand-rechts:[ ]
rechter Abstand
padding-bottom:[ ]
abstand-unten:[ ]
unterer Abstand
padding-top:[ ]
abstand-oben:[ ]
oberer Abstand
page-break-after:[ ]
seitenumbruch-danach:[ ]
Seitenumbruch nach dem Element in Verbindung mit always, avoid, left, right, inherit, auto
seitenumbruch
Abkürzung für seitenumbruch-danach:always
color:[ ]
farbe:[ ]
Farbe in Verbindung mit Farbnamen
background-color:[ ]
hintergrundfarbe:[ ]
Hintergrundfarbe in Verbindung mit Farbnamen

Plotten

Das Plotten ermöglicht es Daten als Punkte auszugeben. Damit können beliebige Grafiken erzeugt werden. Die Plotdaten müssen einem bestimmten Schema entsprechen, das im folgendem beschrieben wird.
In einer Kollektion von Tupeln wird der erste Wert eines Tupels als X-Wert angesehen. Alle weiteren Werte des Tupels als Y-Werte. Diese Y-Werte können auch in Kollektionen und Tupeln sein.
Folgendes Beispiel plottet zwei Funktionen:
aus <L(X):-2 to 2 step 0.005>    # X-Werte
ext GERADE:=0.5 * X              # Funktion 1
ext PARABEL:=X * X + X -2        # Funktion 2

Will man die Fläche zwischen den Funktionen plotten (image klicken), so kann man dies durch Erweiterung des X, Y1, Y2 Tupels um die Kollektion K tun:
ext K:=if GERADE < PARABEL then <L(Z):GERADE to PARABEL step 0.01>
                           else <L(Z):PARABEL to GERADE step 0.01>

Um Punkten eine andere Farbe zu geben, muss man die Daten um Farbinformationen erweitern. Eine Farbinformation ist ein Tupel mit dem Tagnamen RGB. RGB steht für rot-grün-blau. Das Tupel besteht aus drei PZAHL Werten im Interval [0., 1.]. Ein Wert gibt den Farbanteil für rot, grün oder blau an. Gibt man die Werte als ZAHL an, so ist das Interval [0, 255]. Will man einen Punkt färben, so muss man ein Farbtupel vor diesem Punkt definieren. Der Punkt und alle folgenden Punkte werden dann in der entsprechenden Farbe geplottet. Die folgende Erweiterung färbt die Funktionen rot und blau und füllt die Fläche dazwischen mit einem Farbverlauf.
ext RGB:= (0.5*X,Z*0.1,Z*0.2) leftat K   # Farbverlauf

...

o++oPS Web-Interface

The o++oPS Web-Interface consists of three areas: above program area, below output area, and between command area.

Program Area

The program area (white) is an editor component. Here o++oPS-programs can be entered and edited .

Command Area

Execute

The buttons "tab", "ment", "hsq", "image", "graphic", "html", "xml", "csv" and "ocaml" execute the program of the input field.
The checkbox "autoclear" causes for the outputs "tab", "ment", "hsq", "html", "xml" and "ocaml", that all old results will be deleted before the new output is printed. With "graphic" and "image" this information is ignored, because always the old output is replaced by the new one.

Load and Store

The buttons "load"/ "save", the arrow and the input field between are responsible for loading and storing. "load" allows to load o++o-programs and tab- and XML-files. With the "save" button you can store either o++o-programs or the output. The arrows decides, whether to store the content of the program or output area. By clicking the arrow the direction can be changed. The file name has to be inserted before storing.

Output Area

In this green area the results of o++o-programs are displayed. If we move the mouse pointer into above right corner, then a "show" button appears. With this the output can be opened in a new window.

A Proposal for the Usage of the System

  1. If possible, load a program, which solves the problem approximately.
  2. Modify the o++o-program if necessary (additional or other program lines, other values, other column names, other operations)
  3. If we have not found a suitable o++o-program, then load a table name (tab, ment, hsq, xml, or csv)
  4. Click meta and tab and copy desired tags (column names) into program area.
  5. If necessary open o++oPS in a second window or second tab of the browser. Search desired words by running queries of the following form:
    aus file name
    gib M(column name)
    Now, you can copy corresponding words or elements to program area of the first tab (window). Repeat this for other files or column names.
  6. Corresponding keywords, you can find in keywords.pdf.

28 o++oPS-Examples

o++oPS is an end-user programming language, which allows repeating groups easily to handle. It allows an easy formulation of queries to tables and documents. Because the language does not aim only to formulate queries we call her now o++oPS (otto programming script) and not only ottoQL (otto query language). This project was influenced by CONVERT, SQL, XML and XQuery. o++oPS differs from "ottoQL" not only by syntactical changes, but also by semantic ones.

1. A Repeating Group

Some basic features will by explained with the help of the following table ottos.tab. The examples can be tested with the system http://ottops.eu.
M(NAME,                  BORNIN,      L(ACT,                                   YEAR))
  Otto the Great         Old Saxony(De) elected to the king of Germany          936
                                        beat the Hungarians on the Lechfeld     955
                                        first emperor of the Holy Roman Empire  962
  Otto von Moravia       Moravia        married Euphemia of Hungary            1086
  Otto von Bismarck      Prussia(De)    "Zuckerbrot und Peitsche" policy       1871
                                        Emser Depesche                         1870
                                        first chancellor of Germany            1871
  Nikolaus Otto          Taunus (De)    cooperative inventor of the Otto motor 1876
  Otto von Guericke      MD (De)        inventor of the air pump               1649
                                        hemisphere experiment for the emperor  1654
  Otto Normalverbraucher De             learned car driving                    1960
                                        learns a programming language          2020
This table contains a set (M) of 6 persons and for each person a repeating group (L(ACT, YEAR))- a list of (ACT, YEAR)-pairs.
"Zuckerbrot und Peische": with a carrot and a stick
"Otto Normalverbraucher": average Joe

2. Meta Data

Program 1: Give me the meta data of the table ottos_eng.tab.
aus ottos.tab
(click "meta" and "tab")
The result is a complete TTD:
TABMENT: OTTOS
OTTOS: M(NAME,BORNIN,L(ACT,YEAR))
NAME,BORNIN,ACT: TEXT
YEAR: ZAHL
TABMENT is an artificial word consisting of TABle and docuMENT. It describes the type of the current table. TTD abbreviates „Tabment Type Definition“. ZAHL is a number (integer of arbitrary size). If you want to see the results of a query in form of a tab-table, "meta" is to switch off. All following programs are sequential. They start with a table (of the "aus"-part for example) and all following operations are applied to the result of the preceding line.

3. Example Programs

3.1 Playing „Hello World“

Program 2: Print two words.
Hello World
The result is a list of words (L(WORT)).
Program 3: Give me a pair of two words.
Hello, World

Here comma divides components of tuples. A tuple (a pair is a 2-tuple) in the output is arranged in general horizontally and elements of collections (lists (L), sets (M), bags (B)) vertically. In some simple situations collections are also arranged horizontally to save space.
Program 4: Print a text with empty space.
"Hello World"

Program 5: Concatenate two words

Hello ^ World # ^: concatenation of text
"#" is for line comment.
Program 6: Print a greeting with a list of words.
ext GREETING:=<Hello World>
"ext" = extension; extension of the empty table by a column. The result is a list of two words.
Program 7: Print two words with two column names.
ext DEAR:=Hello
ext GREETING:=World

The result is a pair (2-tuple) of two one-column tables.
Program 8: Print a text with empty space with one column name.
ext GREETING:=“Hello Welt“
Program 9: Sort a set of words.
ext GREETING:=<M:World Hello>

3.2 Selection a la Google

Program 10: Give all records, which contain the word "Lechfeld".
aus ottos.tab
mit Lechfeld

3.3 More precise Selection

Program 11: Print all data about Guericke.
aus ottos.tab
mit Guericke in NAME

Column names contain in o++oPS-programs only capital letters. If a word contains a small letter, then it is interpreted as TEXT (string). If the text has to contain empty spaces, then it has to be written in quotation marks (for example: “Otto von Guericke“). Keywords are written in small letters.
"in": each word of the left side is contained in the right side. Capital and lower-case letters are not of importance.
Program 12: Give all persons, born in Germany.
aus ottos.tab
mit De in BORNIN
Program 13: Find all persons, who are not nobles.
aus ottos.tab
ohn Von in NAME
"ohn" abbreviates "without".

3.4 Restructuring

Program 14: Find all acts of Otto the Great.
aus ottos.tab
mit “Otto the Great“ in NAME
gib L(ACT)
Program 15: Give for each year all acts with name.
aus ottos.tab
gib M(YEAR, L(ACT, NAME))

With "gib" (give) you can restructure in an arbitrary way. The user can give an arbitrary scheme or a partial TTD. The above records are sorted by year. Besides sets (M) also bags (B) are sorted by "gib". With the help of "M-(A1,A2,...)" or "B-(A1,A2,...)" the collections are sorted by A1,A2 downwards. With "L" the input order is maintained and with "L-" it is inverted.

3.5 Forget Columns

Program 16: Give all data of the 19th century without the column YEAR.
aus ottos.tab
mit YEAR >= 1800 & YEAR < 1900
weg YEAR
"weg" stands for away.

3.6 Aggregations in different Source Levels.

Program 17: How many persons and how many acts contains the file ottos_eng.tab.
aus ottos.tab
gib CNTPER, CNTACT CNTPER:=cnt(NAME) CNTACT:=cnt(ACT)

3.7 Aggregations without GroupBy in several Target Levels

Program 18: Find the number of persons for each century and the number of acts.
aus ottos.tab
ext CENTURY:=zahl(YEAR : 100) +1
gib CNT_PER,M(CENTURY,CNT_ACT) CNT_PER:=cnt(NAME)
    CNT_ACT:=cnt(ACT)
By „&&“ two lines are connected to a logical unit.

3.8 Selection without Having

Program 19: Find all persons with more than 2 acts.
aus ottos.tab
mit cnt(L(ACT)) > 2
Program 20: Find for each century the last two acts.
aus otto.tab
ext CENTURY:=zahl(YEAR : 100) +1
gib M(CENTURY,B(YEAR,ACT))
mit YEAR:: pos-(YEAR) < 3

3.9 Forward Recursion

Program 21: In how many years doubles the economic power, if we have an increase of 1 percent.
aus <L(YEAR): 0 to 100>
rec AMOUNT:= first:1 next:pred(AMOUNT)*1.01 at YEAR
mit AMOUNT <= 2
"rec": recursive extension
"pred": predecessor
The first expression (1) is the value of the first year (0). The second expression (pred(AMOUNT)*1.01) computes the resulting values always from the preceding value.

3.10 Unary Numbers

Program 22: Each of four grand children gets three apples. How many apples are needed?
aus <L(CHILD): Ernst Clara Ulrike Sophia>
ext <L(APPLE): |||> at CHILD # ext: Extension
gib L(APPLE)
cnt
Beside the five elementary data types TEXT, WORT (word), BOOL (2 truth-values "true" and "false"), ZAHL (integers of arbitrary size) PZAHL (numbers with a point (".")) the data type BAR exists, which contains only one bar (|).
Program 23: (3+4)*5
aus <L(X): |||> , <L(X): ||||>
ext <L(Y): |||||> at X
gib NUM NUM:=cnt(Y)

3.11 Weighted Averages

Program 24: Compute the average, the weighted average, and the average for each subject (inclusive the exams E1 and E2).
<TAB:
M(NAME,L(SUBJECT,   E1?,E2?,L(MARK))::
  Paul   Maths      1   3     1 4
         Art        2   2     1 3 2 1 1
                              1 4 4 1
  Anne   Maths      1   4    
3 2 4 2 :TAB>
#ext AVG1:= avg(E1?,E2?,L(MARK)) at SUBJECT
#ext WEIGHTED_AVG := 0.6 * avg(E1,E2)+ 0.4 * avg(L(MARK)) at SUBJECT
gib SAVG,M(SUBJECT,SAVG) SAVG:=avg(0.6 * avg(E1,E2)+ 0.4 * avg(L(MARK)))
rnd 2

By "rnd 2" all numbers are rounded to 2 digits after ".". The weighted average is defined only if both exams exist.

3.12 Analyze Bank Accounts

Program 25: How much I paid 2013 and how much 2014 for electricity.
aus umsatz2013.csv, XX:=umsatz2014.csv
mit Strom
gib COSTS13,COSTS14 COSTS13:=sum(UMSATZ2012/BETRAG) &&
    COSTS14:=sum(XX/BETRAG)

By the comma in the aus-part both tables are not connected, but only put one beside the other, such that for both "Sparkasse"-files the following TTD results:
TABMENT: UMSATZ2013, XX
UMSATZ2013, XX: L(....,VERWENDUNGSZWECK,..., BETRAG,...)
VERWENDUNGSZWECK,...: TEXT
BETRAG: PZAHL

3.13 Connecting two tables

The following programs refer to two flat (relational) student tables of the following types:
students1.tab: M(STID, NAME, LOC?, SAL, DEPT)
exams1.tab: M(STID, COURSE, MARK)
Program 26: Find all students, who realized a course with the word Algebra. But print all exams of these students.
aus students1.tab
ext exams1.tab at DEPT
mit STUDENTS1/STID=EXAMS1/STID
weg EXAMS1/STID
mit Algebra in EXAMS1

After omitting of the redundant column STID (weg) the current tabment has the following TTD:
TABMENT: STUDS
STUDENTS1: M(STID, NAME, LOC?, SAL, DEPT, EXAMS1)
EXAMS1: L(COURSE, MARK)
MARK, STID: ZAHL
COURSE, DEPT, NAME, LOCATION, SEX: TEXT
Program 27: Find all students, who realized the course „Algebra" with 1, with all courses, they realized.
aus students1.tab
ext {aus exams1.tab; mit STID=STID'; weg STID} at DEPT
mit STID:: (Algebra,1) in2 EXAMS1
After extension „ext“ the current tabment has also the above TTD. Within the subprograms, determined by „{}“, we can refer by „'“ to the next outer column names. „in2“ represents the element relation and set-theoretical inclusion, resp. bag or list- inclusion.

3.14 Generation of a small Image

Program 28: Generate the points of the sine-function and the first derivation in the interval [-4,4]. Add an X-axis with 7 bars at integers.
aus <L(X): -4 to 4 step 0.01>
ext SINE:= sin(X)
ext DERIVATION:=(sin(X+0.001)-sin(X)) : 0.001
ext Y:=0 at X
ext <L(X2): -3 to 3>
ext <L(Y2): -0.05 to 0.05 step 0.01> at X2

The "ext", which introduces "L(X2)" can also be replaced by a comma. Here it is presupposed that „image“ was clicked.

4. Literature

Additional Functions in o++oPS

1 Variable

To handle data in the background we can use variables in ottoPS.
The syntax for saving the values is as follows:
$NAME := expression
Here NAME is the name of the variable and the expression is any Function.
Example:
$C := 1 + 2, 3
There is also the possibility to save the current tabment.
The syntax is =: $NAME
Example:
1, 2
=: $C
User has access to the variable through a variable name in capital letters in the expression with the dollar sign placed in front.
Example:
ext B1:= $C + 5
$C := $C + 1

Global Variable

Current variables are valid only locally. And if we want the variables to be used also outside the actual program and also in the later added programs then we can use global variables. These are marked by two dollar signs.

2 Functions

The syntax of a function definition is:
function NAME ($P1, $P2, ... $Pn) BLOCK
The parameters are variables from P1 to Pn. BLOCK is either a single o++PS-command or a o++oPS-program, that lies in between begin and end. Example:
function ADD0 ($C, $D) $C + $D

function FE ($C) begin
$C
ext $C + 23
end

A function can be called in the following way.
$X:=1,2
aus ADD0($X,8)

It is possible to access to the variables from outside of the function definition. Changes to these variables and creating new variables will be lost however after the execution on the function.

3 Include

With include it is possible to load program code from other files.
The syntax is:
include expression
The expression must be of type TEXT with a file name.
Example:
include "functions.otto"
The inserted program has control over outside defined variables, however the changes to these variables are not passed to the calling program. Only the defined functions are given over to the calling program. Also the current tabment will not be changed. Exceptions are the global variables.

A Tabment Definition

Tabment is an artificial word, composed of TABle and docuMENT. It can be considered as a semantic precision of an XML-document, where the concrete XML-syntax of primary data is only one of several representation possibilities. Many tabments can be advantageously represented as (structured tables). Certain tables can be interpreted as collections of points eventually with an color value, such that they can be interpreted also graphically as an image. The tabment in its restricted version was firstly specified with an Algebraic specification language of Kaphengst Reichel. Then the approach was implemented in CAML-Light. With the rise of XML, it was generalized to documents. This generalization we represent here in OCAML notation (Objective CAML). To guarantee that this precision remains clearly arranged, we do not include improvements, which aim on an more efficient implementation.

1. Specification of the Tabment Notion

Tabments are very general objects. Numbers, text,..., sets, bags (multisets), and Lists are tabments. These objects are collected in one sort (one type) tabment. For this we need only 4 simple auxiliary sorts: collection symbols for different kinds of collections; names as a type for simple tags (column names), elementary values and schemes, which describe the direct type of the tabment. If additionally each name is described by a scheme, then we have a TTD (Tabment Type Definition) of the tabment. For the TTD, we don't need a new sort, because it is of type L(NAME,SCHEME) (L=list). We introduce 3 proper collection symbols (M, B, L) and one symbol for optional values. "S1-collections" contain zero or one element. The collection symbols M-, B-, L- are needed only for sorting purposes. The possibilities for the Any-collection are not yet exhausted. Its elements are allowed to posses different types. Therefore, this type seems to be interesting for NoSQL-approaches.
type coll_sym =
  Set | Bag | List (* M, B, L *)
| Set_minus | Bag_minus | List_minus (* M-, B-, L- *)
| S1 (* ?: optional values *)
| Any;; (* A *)
type name = string;; (* column names, tags *)
type big_int = Big_int.big_int
type value = (* elementary values *)
  Bar (* |: the stroke in the unary system of numbers *)
| Int_v of big_int (* each number is a value *)
| Float_v of float
| Bool_v of bool
| String_v of string
| Stringi_v of string;; (* word *)
type scheme =
  Empty_s (* empty scheme: error value *)
| Inj of name (* each name is a scheme *)
| Coll_s of coll_sym * scheme (* scheme of a collection *)
| Tuple_s of scheme list (* scheme of a tuple *)
| Alternate_s of scheme list;;(* scheme for Choice *)
type tabment =
  Empty_t (* empty tabment: error value *) | El_tab of value (* each value is a tabment *) | Tuple_t of tabment list (* tuple of tabments *)
| Coll_t of (coll_sym * scheme * (tabment list))
    (* Coll_t (c,s,[t1;t2;...;tn]) is a collection of n tabments t1,t2,t3...tn *)
| Tag0 of name * tabment
    (* Tag0(n,t): t is enclosed within a tag n *)
| Alternate_t of (scheme list) * tabment;;
    (* Alternate_t([s1;s2;...;sn],t) t has to be of type s1 or s2,... or sn *)

2. Examples to illustrate the Tabment Specification

t1 = El_tab(String_v “Ernst“) = <TEXT: Ernst>
   = <TEXT>Ernst</TEXT> = <TABM>Ernst</TABM>
t2 = Tag0("NAME", (El_tab(String_v “Clara“))) = <NAME: Clara>
   = <NAME>Clara</NAME>
t3 = Tag0("NAME", (El_tab(String_v “Josephine“)))
   = <NAME: Josephine>
t4 = Tuple_t [t2; t3] (one person)
   = << NAME, NAME::
        Clara Josephine >>
   = <NAME>Clara</NAME>
     <NAME>Josephine</NAME>
t5 = Coll_t (List, Inj“NAME“, [t2; t3] ) (two persons)
   = <<L(NAME)::
         Clara
         Josephine>>
   = <<L(NAME)::
         Clara Josephine>>
   = <NAME>Clara</NAME>
     <NAME>Josephine</NAME>
t6 = Tuple_t[Coll_t((S1,Inj “A1”),[Tag0(“A1”,El_tab(Int_v 10))]);Coll_t((S1,Inj “B1”),[])]
   = <<A1?, B1? ::
       10 >>
   = <A1>10</A1>
The schemes of the above tabments:
type_t (t1) = Inj “TEXT”= TEXT
type_t (t2) = type_t(t3) = Inj “NAME” = NAME
type_t (t4) = Tuple_s[(Inj “NAME”); (Inj “NAME”)] = (NAME, NAME)
type_t (t5) = L(NAME)
type_t (t6) = Tuple_s[Coll_s(S1,Inj”A1”),Coll_s(S1,Inj”B1”)] = (A1?, B1?)
The TTD's of the above tabments:
ttd_t (t1) = [“TABMENT“, Inj“TEXT“]
ttd_t (t2) = [“TABMENT“, Inj “NAME“; “NAME“, Inj “TEXT“]
ttd_t (t3) = ttd_t (t2)
ttd_t (t4) = [”TABMENT“,Tuple_s[(Inj “NAME”);(Inj “NAME”)];“NAME“, Inj ”TEXT“]
ttd_t (t5) = [”TABMENT“, Coll_s(List, Inj”NAME”);“NAME”,Inj”TEXT”]
ttd_t (t6) = [”TABMENT“,Tuple_s[Coll_s(S1,Inj”A1”);Coll_s(S1,Inj”B1”)]; “A1”,Inj “ZAHL”]

3. Tabments in Practice

A flat relation in the sense of the Relational data model is a tabment of type
   M(A1,A2,...,An).
From practical point of view "?"-marks can be added to represent null values and the set symbol (M) can be replaced by a bag (B) or a list (L) symbol. Most csv-tables have the same type.
NF2-relations contain repeating groups in arbitrary depth and they are therefore of type
   M(A1,A2,...,M(B1,B2,...M(C1,C2,...),M(...)),M(...)...),
where all Ai, Bi, Ci,... are of elementary type. A traditional database is of type
   FILE1, FILE2,...,FILEn,
where each file (relation) is of the above mentioned file. An XML-document with DTD (Document Type Definition) is a tabment. The distinction between collection and tuple is described in the DTD. This is not visible in the XML-document. Therefore, it is hard for the tabment approach to consider XML-documents without DTD. Because of this general understanding of XML we can consider Wikipedia documents also as tabments. Therefore, we hope to implement in future also queries on the Wikipedia. The tabments of o++oPS are proceeded in RAM. If we would save large amounts of corresponding RAM-space (omit redundant pointers and tag data), then our implementation can hopefully be extended to an In-Memory-database.

4. Tabment Operations

A data type is not only a set of elements, but a set with corresponding operations. Because the notion of tabment is very general, operations in many different ways can be defined. Single values are tabments, therefore the ordinary arithmetic operations (+,*,...) and text operations can be generalized to tabments. The same holds for vector- and matrix-operations. The set theoretical operations of the relational algebra (union, intersection, set difference) can also be generalized to tabments, but they are in the case of tabments with repeating groups of small practical importance. The selection can be generalized, but position selecting operations and many sophisticated conditions are needed, too. In o++oPS the projection is replaced by a very general restructuring operation (gib-clause) and by a simple forget-Operation (weg-clause). The Cartesian product does not occur in the set of operations, but it is not difficult to replace it by an extension (ext) and a gib-clause. By "ext" new (complex) columns are introduced. The operations are illustrated in the paper „28 ottoPS Examples“.

Formatted Output with o++oPS

The standard form for the representation of the output is the structured table. This can be in text form as ASCII-formatted table or as table in a HTML document.
The output in HTML makes it also possible to represent the data in other layouts. In addition it needs format information. These are similar to those of the perhaps already well-known formatting language CSS (Cascading Style Sheets). The schema of the format information is L(SELECT, TYPE, L(STYLE)).
Example:
ext FORMAT := &&
<<L(SELECT,     TYPE,   L(STYLE))::
    DOCUMENT    div
    L(ARTIKEL)  table     ohnerahmen fett>>

The additional tag "FORMAT" around this structure is allowed but not necessary.
The column SELECT selects to which parts of the data a format is assigned. For this one can use a tag name. Collections without name can also by L(INSIDETAG) (as in the example) to be addressed. The column TYPE specifies roughly the type of representation. Some possible values are table (table), div (general range), span (inline range), img (picture) and svg (plotten). (In the HTML document these tags play again their role.) In the column L(STYLE) the actual formatting are indicated. Here all CSS characteristics are available. In addition, for user friendliness additional abbreviations are also introduced. Thus one can use instead of CSS characteristic "font weight: bold" only "bold".
Example:
ext LIST1:= <L(X):: 1 to 3>
ext LIST2 := <L(Y):: 1 to 3*X step 2>
ext Z:= Y + 1
replace X by "Table " ^ text(X)

ext &&    # format
<<M(SELECT,        TYPE,       L(STYLE))::
    LIST1          div  
    LIST2          table         rotation:1 margin-bottom:2em
    Z                            color:red >>
The outer collection (LIST1) is not output as a normal table but it is output as a general range by div. The X-elements are also given out as "div", because these formats are further inherited automatically as long as no other format are available. The internal collections (list2) are output as tables because its "TYPE" is "table". The Z-column is colored additionally red.

Remarks for the application of div and span

Both "div" and "span" define a range. With "div" in the text a new block is introduced. That is, that before and after "div" line breaks occur. This can be use for example to arrange paragraphs. With the "span" there are no line breaks, it allows formatting in the running text. This makes it possible to format individual words in the running text.
Example:
ext FIRSTNAME:=Frank
ext SURNAME:=Schulz
ext ROAD:= "Waldweg 3"
ext ZIP:= "09123"
ext CITY:=Eindorf
tag ADDRESS

ext && # format
<<M(SELECT,        TYPE,       L(STYLE))::
    ADDRESS        div           
    FIRSTNAME      span
    SURNAME        span
    ZIP            span
    ROAD           span
    CITY           span >>
Here the address is given output as "div". Without further data all elements of the address would be output in one own line. Firstname/surname and postalcode/city should be placed together in each case in a line. Therefore they are output as a span.
It is also possible to begin with "span". Then all elements of the address would appear successively in a line. If one makes however the road to "div" then appears before and after the road a line break and the address looks as usual.
<<M(SELECT,        TYPE,       L(STYLE))::
    ADDRESS        span           
    ROAD           div>>

TYPE

In the TYPE Column all HTML tags are allowed. Some important are listed in the following overview.

TYPE
Description
table
table
Representation as table
In the column STYLE additional following keywords are permitted:
  • rotation, rotation:n
    the entire table turns around 90 degrees against the clockwise direction. If the table contains internal tables then n describes up to which depth the tables has to be turned on. The resulting columns can be addressed in the SELECT column with the table name [column number]. Data columns have then the TYPE td (table DATA) and the head column the TYPE th (table head)li>
  • ohnerahmen
    by pre-setting the tables are output with gridlines. The keyword "ohnerahmen" switches this off.
  • ohnekopf
    the table is represented without head
div
General range
span
inline range
img
image output: the element concerned should contain a file name or URL
svg
plot
h1
h2
h3
h4
h5
h6
Heading

STYLE

In the STYLE-column all CSS-Characteristics are permitted, In addition there are also short forms allowed.

STYLE
Description
font-weight:bold
bold
bold
font-weight:bolder
extrabold
extra bold
font-weight:lighter
thinner

font-style:italic
kursiv
italic
font-style:oblique
schraeg
oblique
width:[ ]
breite:[ ]
Gives the width of an element. Useful for tables and pictures,
Example: width:250px
height:[ ]
height:[ ]
gives the height of the element
text-decoration:underline
unterstrichen underline
underline
text-decoration:overline
overline ueberstrichen
overline
text-decoration:line-through
line-through durchgestrichen
line-through
text-decoration:blink
blink blinkend
blink
text-indent:[ ]
indent:[ ]
indent
line-height:[ ]
zeilenhoehe:[ ]
line-height
vertical-align:[ ]
vertikale_ausrichtung:[ ]
vertikaleausrichtung:[ ]
vertikale-ausrichtung:[ ]
Vertical adjustment in connection with top, middle, bottom, baseline, sub, super
example: verticale-align:top
text-align:[ ]
textausrichtung:[ ]
text-ausrichtung:[ ]
ausrichtung:[ ]
Textalign (horizontal) in connection with left, right, center, justify.
example: align:block
font-size:[ ]
schriftgroesse:[ ]
groesse:[ ]
Character size in connection with xx-small/very small, small, medium, large, x-very large, xx-anormous large
margin-left:[ ]
rand-links:[ ]
left side margin
margin-right:[ ]
rand-rechts:[ ]
right side margin
margin-bottom:[ ]
rand-unten:[ ]
bottom margin
margin-top:[ ]
rand-oben:[ ]
margin top
padding-left:[ ]
abstand-links:[ ]
distance on left side
padding-right:[ ]
abstand-rechts:[ ]
distance on right side
padding-bottom:[ ]
abstand-unten:[ ]
distance from bottom
padding-top:[ ]
abstand-oben:[ ]
distance from top
page-break-after:[ ]
seiten-umbruch-danach:[ ]
Page break after the element in connection with always, avoid, left, right, inherit, auto.
seitenumbruch
Abbreviation for seitenumbruch-danach:always
color:[ ]
farbe:[ ]
color in connection with color names
background-color:[ ]
hintergrundfarbe:[ ]
Background color in connection with color names

Plots

Data can be considered as points and plotted. Thus arbitrary diagrams can be shown (click image). The plotted data must correspond to a certain scheme, which is described in the following. In a collection of tuples the first value of a tupels is regarded as X-value. All the further values of the Tupels are then Y-values. These Y-values can be also in collections and tuples.
The following example plots two functions:
<L(X)::-2 to 2 step 0.005>    # X-values
ext LINE:=0.5*X                  # function 1
ext PARABOLA:=X*X + X - 2 at LINE             # function 2

If one wants to plot the area between the functions, then one can use collections K of Y (LINE, PARABOLA) tupels for each X-value:
ext K:= if LINE < PARABOLA then <L(Z):LINE to PARABOLA step 0.01>
            else <L(Z): PARABOLA to LINE step 0.01>

In order to give to points another color, one must extend the data by color information. Color information is a tuple with the tag name RGB. RGB stands for red green blue. A tuple consists of three PZAHL values in the Interval [0. , 1.]. A value indicates the color portion for red, green or blue. If you use NUMBER (ZAHL) values, then the Interval is [0, 255]. If one wants to color a point, then one must define a color tuple infront of this point. The point and all following points are then plotted in the corresponding color. The following extension colors the functions red and blue and fills the surface between them with a colour tone.
ext RGB:= (0.5*X, X, Z*0.2) leftat Z   # color tone

...