Kurzbeschreibung von o++oPS


0 Einführendes Beispiel

Die Arbeit mit o++oPS unterscheidet sich sehr von der Arbeit mit EXCEL. Wie es für Datenbanken üblich ist, sind in einer Tabelle bzw. in einem Dokument lediglich Daten enthalten. Formeln und Bedingungen befinden sich in (.otto) -Programmen. In der Regel folgt auf eine Anfrage (Ausführung eines o++oPS-Programm) der Aufruf eines modifizierten oder neuen o++oPS-Programms. Damit verschwindet das Ergebnis der vorangegagenen Anfrage. Wenn man das Ergebnis eines Programms oder das Programm selbst speichern will, ist dies problemlos mit dem save-Button möglich. Der Pfeil ist lediglich in die richtige Richtung zu stellen und der Dateiname in das Feld neben dem Pfeil einzutragen.
Das System enthält insbesondere eine Datei namens "schuelers.xml", die unten näher beschrieben wird. Diese enthält den Namen, Vornamen mehrerer Schüler und einige Fächer mit Noten. Eine große Klasse von Anfragen wollen wir mit dem folgenden Beispiel beschreiben: Gesucht sind für jede Mathematiknote die Schüler, die diese bekommen haben und die Anzahl, wie oft jede Note vergeben wurde und die Anzahl der Mathematiknoten insgesamt. Vom Vornamen soll lediglich der erste Buchstabe ausgegeben werden.
Programm 0:
aus schuelers.xml
avec FACH=Mathe
ext NAME2:= (VORNAME subtext (1,1)) +text "." +text NAME
gib ANZ,(NOTE,ANZ,NAME2m m) ANZ:= cnt NOTE
Durch einen avec- (oder sans-) Teil wird selektiert, d.h. Bestandteile, die der Bedingung nicht genügen, werden verworfen. Textwerte enthalten Kleinbuchstaben oder werden in Hochkomma gesetzt (z.B. "SAP" und Spaltennamen (Tags) enthalten keine Kleinbuchstaben. Anschließend werden im ext-Teil (Extension=Erweiterung um neue Spalten) für jeden Vornamen der erste Buchstabe mit dem Punkt und mit dem Namen verkettet (^). Typische andere Operationen, die spaltenweise angewandt werden, sind die Addition, Multiplikation, u.s.w.. Am Ende findet eine Umstrukturierung mit Sortierung nach den jeweils ersten Namen der entsprechenden Mengen (M) statt (Hier wird die äußere Menge nach NOTE und die innere nach NAME2 sortiert.). Das erste Auftreten von ANZ ergibt die Gesamtanzahl der Noten und das zweite die Anzahl pro NOTE.
Jede dieser drei Programmzeilen kann entfallen. Es können auch jeweils zwei oder mehr mit-Teile oder ext-Teile aufeinander folgen oder sie können einander abwechseln. Es ist aber stets von Vorteil die Selektionen so früh wie möglich durchzuführen, damit die weiter zu verarbeitenden Datenmengen entsprechend klein werden. Durch Anklicken von Beispiel0 und anschließendem anklicken von tab, graphic oder xml erhält man das Ergebnis.

1 Einführung

Unsere Endnutzercomputersprache o++oPS wurde ursprünglich als Datenbanksprache für  Tabellen mit Wiederholgruppen  (non-first-normal-form relations)  entworfen. Mit dem Aufkommen von XML haben wir sie auf (XML-) Dokumente verallgemeinert. Die wichtigsten Besonderheiten von o++oPS sind:
  1. Die Programmlogik ist sehr einfach; die Operationen werden sequentiell (eine nach der anderen) angewandt.
  2. Wir haben komplexe, ausdrucksstarke Operationen für strukturierte Daten, die leicht zu handhaben sind.
  3. Insbesondere haben wir einen ausdrucksstarken gib-Teil , mit dem man simultan restrukturieren, aggregieren,  Duplikate entfernen und vereinigen  kann. In mehreren Schritten kann man sogar beliebige "joins" realisieren.
  4. Im Hintergrund steht eine formale, algebraische Spezifikation von XML-Dokumenten.
  5. Abstrakte XML-Dokumente (TABMENTe) können als TABellen, DokuMENTe, HSQ-Strukturen oder in bestimmten Situationen auch grafisch dargestellt werden.
Die folgende o++oPS-Beschreibung umfasst nur einen Teil der Möglichkeiten, die o++oPS bietet. Es sind aber genug, um mit o++oPS arbeiten zu können. Ein o++oPS-Programm kann auf eine Tabelle (tab), ein Dokument (ment) ein (XML)-Dokument mit DTD, eine csv-Datei mit Metadaten oder eine hsq-Struktur angewandt werden. Das Ergebnis des Programms ist wieder ein Tabment (TABelle+dokuMENT). Ein und dasselbe Tabment kann als Tabelle (tab), Dokument (ment), hsq-Struktur, csv-Datei, XML-Dokument, HTML-Dokument oder gerendert (graphic) ausgegeben werden. Besteht das Tabment nur aus Zahlen, so kann es auch unmittelbar als Bild (image) dargestellt werden. Das XML-Dokument schuelers.xml enthält Daten von 9 Schülern, die den Metadaten entsprechen. Der dritte Schüler Michael Schulz hat beispielsweise in zwei Fächern (Chemie und Deutsch) 10 bzw. 2 Noten. Jeder Schüler mit Namen, Vornamen und Fächern ist durch eine „SCHUELER“- Markierung (Tag) eingerahmt. Jedes Fach mit den entsprechenden Noten ist durch einen FACHTUP-Tag eingerahmt. TUP kommt von TUPEL. Ein TUPEL ist eine Verallgemeinerung des Begriffs Paar (von zwei Komponenten) auf n-Komponenten. (Meier, Hans, Mathe) ist beispielsweise ein (NAME, VORNAME, FACH)-Tripel (3-Tupel). Die Darstellung als XML-Dokument ist konzeptuell sehr vorteilhaft, da man genau erkennt, dass eine Zahl eine Note ist und welches Wort ein Name, Vorname oder Fach ist. Allerdings kann man obiges XML-Dokument in der folgenden Weise platzsparender in Form einer Tabelle ausgeben. Damit passt dieses Dokument bequem auf einen (kleinen) Bildschirm oder ein kleines Blatt Papier.
    NAME,   VORNAME,       (FACH,   NOTEl l) l
    Meier   Hans Peter Paul Mathe   1 1 1
    Mueller Antje           Mathe   2 1
                            Deutsch 4 1 2 4 1 2
    Schulz  Michael         Chemie  1 4 4 4 4 4 4
                                    4 4 4
                            Deutsch 1 4
    Schulz  Michael         Deutsch 1 1 1 2 2 1 1
                                    1 1
                            Mathe   1 4
    Schmidt Max             Mathe   1 4 2 1 4 2 1
                                    4 2
                            Chemie  4
    Mayer   Fritz           Mathe   3 1 3 1 3 1 3
                                    1 3 1
                            Physik  2
    Chang   Lee             Mathe   2 2 1
    Perner  Nadin           Deutsch 1
                            Mathe
    Mayer   Fritz

Hier geht der Bereich einer Spalte vom ersten Buchstaben der Spalte bis ein Zeichen vor dem ersten Buchstaben der nächsten Spalte. In der ersten Zeile gehört somit der Vorname „Hans-Peter-Paul“ vollständig zur VORNAME-Spalte. Dieses Tabment ist völlig gleichwertig zum XML-Dokument, wenn klar ist, dass hier die gleiche Otto-DTD (DTD=Document-Type-Definition, das sind Daten über Daten) vorliegt.
In unseren Fall haben die Metadaten folgendes Aussehen:
    TABMENT: SCHUELERS
    SCHUELERS: SCHUELERl
    FACHTUP: FACH,NOTEl
    SCHUELER: NAME,VORNAME,FACHTUPl
    FACH NAME VORNAME: TEXT
    NOTE: ZAHL
Diese TTD (TabmentTypDefinition) (otto-DTD) besagt, dass das Tabment durch einen SCHUELERS-Tag-umschlossen ist, dass SCHUELERS eine Liste (L) von SCHUELER-Daten ist, dass ein Schüler ein Tripel aus NAME, VORNAME und einer Menge (M) von FACHTUPeln ist und ein FACHTUPel aus einem FACH und einer Liste von NOTEn besteht. NAME, VORNAME und FACH sind atomare Textdaten, und NOTE ist eine (ganze) ZAHL. Wenn diese Metadaten nun zu obigem Tabment gehören, so enthält die computerinterne Darstellung des Tabments auch die Tags SCHUELERS, SCHUELER und FACHTUP, obwohl diese nicht sichtbar sind. Die Verwendung dieser Tags in der tabellarischen Darstellung würde die Übersichtlichkeit der Tabelle beeinträchtigen. An diesem Beispiel wird schon klar, dass eine Otto-TTD einfacher als ein gewöhlicher XML-DTD aussieht.
Wir benutzen in o++oPS englische und einige kurze deutsche Schlüsselworte.
m: von „Menge“, die Mengentheorie wurde von G. Cantor entwickelt.
l: von „Liste“,
b: Bag (englisch): Multimenge
gib: (kann mit dem SELECT von SQL verglichen werden, hat jedoch eine breitere Funktionalität)
aus:  (FROM von SQL)
avec: (WHERE von SQL)
o++oPS unterscheidet 6 atomare Datentypen:
TEXT:
WORT:
ZAHL: (beliebig große ganze Zahlen)
PZAHL: (Kommazahl; aber mit Punkt geschrieben (englisch: float))
BOOL: (Wahrheitswerte) nach dem englischen Mathematiker Boole
BAR: (Der Datentyp enthält nur einen Wert (einen Strich) und ist nur als Liste von Strichen interessant.)
Mit den obigen Kollektionskonstruktoren (m, l, b) , dem Tupelkonstruktor, dem Auswahl (Choice)-Konstruktor und dem Tag-Konstruktor (umschließt ein beliebiges Tabment mit einem Namen) kann man aus den atomaren Typen bzw. Werten schrittweise beliebige komplexere Typen bzw. Tabmente generieren.
Mengen, Multimengen und Listen unterscheiden sich in folgenden Punkten: In einer Menge im Gegensatz zur Multimenge und Liste kommt jedes Element nur einmal vor. In Mengen und Multimengen spielt die Reihenfolge der Elemente im Gegensatz zu Listen keine Rolle. Das heißt zum Beispiel, dass es nicht gleich ist, ob eine „1“ am Anfang oder am Ende steht.
Da die Reihenfolge der Elemente keine Rolle spielt und Nutzer stets übersichtliche Anfrageresultate erwarten, werden Multimengen und Mengen durch eine gib-Anweisung stets sortiert. Das soll durch ein Beispiel illustriert werden, welches ansonsten keine praktische Bedeutung hat:
Programm 1:
aus schuelers.xml
gib NAMEm, NAMEb, NAMEl
Ergebnis (Tripel von 3 Kollektionen):
    NAMEm,   NAMEb,   NAMEl
    Chang    Chang    Meier
    Mayer    Mayer    Mueller
    Meier    Mayer    Schulz
    Mueller  Meier    Schulz
    Perner   Mueller  Schmidt
    Schmidt  Perner   Mayer
    Schulz   Schmidt  Chang
             Schulz   Perner
             Schulz   Mayer

2 Der gib-Teil

Der gib-Teil besteht aus dem Schlüsselwort "gib" gefolgt von einem (Ziel-)Schema. Im Zielschema dürfen auch Namen vorkommen, die nicht im Quelltabment auftreten. Für jeden neuen Namen muss eine Aggregationszuweisung oder eine Typ-Definition angegeben werden. Alle diese Typ-Definitionen repräsentieren eine (partielle) TTD (otto-DTD). Die rechte Seite einer Aggregationszuweisung besteht aus einer Aggregation (sum, cnt,...), die auf einen (Spalten-) Namen oder einen Ausdruck angewandt wird.
Mit der gib-Anweisung kann man viele Probleme lösen:
  1. Sortieren (M, B) (erste und zweite Spalte in Programm 1) Wenn wir ein allgemeineres Zielschema A1,A2,(B1,B2,(...l)b)m haben, dann werden die äußere Kollektion nach (A1,A2) und alle inneren Multimengen nach (B1,B2) sortiert. Wenn die Multimengen beispielsweise zuerst nach B2 sortiert werden sollen, dann muss lediglich die Reihenfolge von B1 und B2 vertauscht werden. Wenn absteigend nach (B2,B1) sortiert werden soll, so muss dem Kollektionssymbol ein "-"-Zeichen folgen: "(B2,B1,(...l)bv"
  2. Duplikate entfernen (m) (erste Spalte im Programm 1) Bei einem Zielschema A1,A2,(B1,B2,(...l)b)m würde jeder (A1,A2)-Wert nur einmal vorkommen. Ein A1-Wert könnte dann trotzdem mehrfach vorkommen.
  3. Umstrukturieren (neues Schema bzw. neue TTD angeben)   
  4. Programm 2:
    aus schuelers.xml
    gib FACH,VORNAMEb m
    In schuelers.xml war das Fach den Vornamen untergeordnet im Anfrageergebnis ist es umgekehrt. Ist ein interner FACHTUP-Tag gewünscht, so kann der gib-Teil in folgender Weise modifiziert werden.
    gib FACHTUPm
        FACHTUP! (FACH,VORNAMEb)
    Wesentlich ist, dass der Nutzer lediglich die TTD (die Metadaten) angeben muss. Das System generiert ein entsprechendes XML-Dokument (Tabment) von selbst. Diese leicht zu handhabende Umstrukturierung gekoppelt mit Aggregationen (siehe unten) ist einer der größten Vorteile von o++oPS. Ein Spezialfall der Umstrukturierung ist das Flachklopfen eines Tabments. Dabei entsteht eine gewöhnliche Tabelle:
    Programm 3:
    aus schuelers.xml
    gib NAME, VORNAME, FACH, NOTE l
    Das Ergebnis besteht aus 59 Zeilen:
        NAME,   VORNAME,        FACH,   NOTE l
        Meier   Hans Peter Paul Mathe   1
        Meier   Hans Peter Paul Mathe   1
        Meier   Hans Peter Paul Mathe   1
        Mueller Antje           Mathe   2
        Mueller Antje           Mathe   1
        Mueller Antje           Deutsch 4
        ...
        Chang   Lee             Mathe   1
        Perner  Nadin           Deutsch 1
    Da der letzte Schüler „Fritz Mayer“ keinen Fach- und keinen Noteneintrag hat, kann er nicht in dieser „normalen“ Tabelle erscheinen. Ferner fehlt der Mathe-Eintrag von Nadin Perner, da hier kein Noteneintrag vorliegt.

  5. Aggregationen (Summe (sum), Anzahl (cnt von count), Durchschnitt (avg von average), Produkt (prd) Maximum (max), Minimum (min), EXISTS (exs), FORALL (all), median, linreg,...)
    Programm 4: Gesucht ist der Durchschnitt für jeden Schüler und pro Fach und Schüler.
    # „#“ ist der Zeilenkommentar
    aus schuelers.xml
    gib NAME, DUR, (FACH, DUR m)l
        DUR := ++: NOTE
    Weil die letzte Zeile mit mindestens 4 Leerzeichen beginnt, gehört sind aus logischer Sicht zur vorletzten Zeile.
    Ergebnis :
        NAME,   DUR?,        (FACH,   DUR? m)l
        Meier   1.            Mathe   1.
        Mueller 2.125         Deutsch 2.33333333333
                              Mathe   1.5
        Schulz  3.5           Chemie  3.7
                              Deutsch 2.5
        Schulz  1.45454545455 Deutsch 1.22222222222
                              Mathe   2.5
        Schmidt 2.5           Chemie  4.
                              Mathe   2.33333333333
        Mayer   2.            Mathe   2.
                              Physik  2.
        Chang   1.66666666667 Mathe   1.66666666667
        Perner  1.            Deutsch 1.
                              Mathe
        Mayer
Da für den letzten „Mayer“ und den letzten Matheeintrag kein Durchschnitt berechnet werden konnte, hat das System den Durchschnitt in einen optionalen Wert (DUR?) umgewandelt. D.h. in einer Tabelle NAME, DUR? l muss im Gegensatz zu einer Tabelle NAME, DUR l nicht zu jedem Namen ein DUR-Wert existieren. Will man den Durchschnitt für jedes FACH haben, so muss man ein Zielschema M(FACH, DUR) wählen, damit ein Fach nicht mehrfach ausgegeben wird und die Durchschnitte richtig berechnet werden. In Programm 4 konnten wir nicht M(NAME, DUR,... schreiben, da sonst die Durchschnitte für jeden Namen und nicht jede Person berechnet worden wären. Wenn man nur den Durchschnitt für jedes Fach und jede Person möchte, so ist eigentlich kein gib-Teil erforderlich, da man die Durchschnittsfunktion avg dann lediglich auf jede gegebene Liste von Noten anwenden muss:
aus schuelers.xml
ext DUR:=NOTEl ++:        # siehe nächsten Abschnitt
Hier wird das gegebene Tabment um eine neue DUR-Spalte erweitert, sodass ein Tabment des folgenden Typs entsteht:
NAME, VORNAME, (FACH, DUR, NOTEl)l)l
Schreibt man dagegen anstelle der letzten Zeile
ext DUR:=NOTE ++:
,so entsteht ein Tabment des Typs
NAME, VORNAME, (FACH, (NOTE, DUR l)l)l,
wobei jeweils nur der Durchschnitt über eine Note gebildet wird. Die beiden letzten Spalten enthalten daher die gleichen Zahlen. Bei der Zuweisung
DUR:= ++: NOTE in obigen gib-Teil ergibt sich die Art der Aggregation DUR aus der Stellung von DUR im Zielschema.

3 Die ext-Anweisung

ext [name :=] expression [(at | leftat) name]
Da uns das Wort extension (Erweiterung) zu lang war, haben wir es durch ext abgekürzt. Ein ext-Teil besteht aus dem Schlüsselwort ext einem optionalen Zuweisungsprefix und einem Ausdruck. Diesem kann optional eines der Schlüsselworte at oder leftat und ein Name folgen. Wenn wir eine Klausel "at n2" gegeben haben, dann wird durch die entsprechende Zuweisung das Quelltabment rechts von jedem Vorkommen von n2 um den Wert des Ausdrucks erweitert. Wenn der Zuweisungsprefix "n1:=" gegeben ist, dann wird  jeder Wert durch den Tag n1 eingeschlossen und das Tabment wird jeweils um den um den Tag erweiterten Wert erweitert. Fehlt "at name",  dann sucht das System nach dem höchsten Namen für eine vernünftige Erweiterung. Dadurch vermeidet die Erweiterung Redundanz.
Programm 5: Berechnung von Fläche und Umfang mehrerer Rechtecke
<TAB:
X,   Y l
3.78 8.99
6.84 8.33
7.32 7.65
:TAB>
ext FLAECHE:=X*Y
ext UMFANG:=X+Y*2
Durch die erste ext-Anweisung wird das gegebene Tabment um eine Spalte erweitert:
X,   Y,   FLAECHE l
3.78 8.99 33.9822
6.84 8.33 56.9772           #  (*)
7.32 7.65 55.998
Hätten wir „leftat X“ geschrieben, so befände sich die Spalte an erster Stelle vor dem X. Da wir at weggelassen haben, hat das System das tiefste rechte Feld, das in dem Term vorkommt betrachtet und erweitert in dieser Ebene rechts. Das heißt, wenn die Tabelle vom Typ
M(X, L(Y, L(Z))) ist, und wir
ext FLAECHE:= X * Y
anwenden, so entsteht ein Tabment vom Typ X, (Y, FLAECHE, Zl l)m.
Im obigen Fall sind X und Y gleich tief, weshalb neben Y erweitert wurde. Das Finden der zu erweiternden Stelle ist sehr schwierig, weshalb das System manchmal durch eine at-Klausel unterstützt werden muss. Wir erkennen am obigen Beispiel, dass eine Formel (oben X*Y) stets auf alle Elemente des Tabments angewendet wird. Nachdem das geschehen ist, wird die nächste Programmzeile wieder auf alle entsprechenden Elemente angewandt. Das heißt jetzt, dass die letzte Zeile von Programm 5 auf das Tabment (*) angewandt wird, weshalb das Gesamtergebnis von Programm 5 folgende Gestalt hat:
X,   Y,   FLAECHE, UMFANG l
3.78 8.99 33.9822  25.54
6.84 8.33 56.9772  30.34
7.32 7.65 55.998   29.94
Wir wollen noch einmal zurück zu einer strukturierten Ausgangstabelle.
Programm 5b:
<TAB:
X,   Yl l
1    4
     6
3    8
     6
:TAB>
ext Z:=X + Y
Ergebnis:
X,  (Y, Z l)l
1    4   5
     6   7
3    8  11
     6   9
Um den Wert für Z zu berechnen, wird X + Y immer zuerst mit einem X-Wert belegt. Für das erste Element ergibt sich der Ausdruck „1 + Y“. Erst wenn man noch tiefer in die Y-Werte hineigeht , ergibt sich jeweils ein vollständiger X+Y-Wert. Für die erste Zeile ergibt sich „1 + 4“ und für die zweite Zeile „1+ 6“. Analog werden die letzten beide Werte berechnet und in die neue Spalte eingetragen. Ersetzt man die ext- Anweisung durch
ext Z:= X + Y at X
, so ergibt sich:
L(X, Z?, L(Y))
  1        4
           6
  3        8
           6
Z-Werte fehlen, da X+Y in der X-Ebene, wo um Z erweitert werden soll, noch nicht vollständig belegt werden konnte. Es existiert zwar zu jedem Y-Wert ein (eindeutig bestimmter) zugehöriger X-Wert, aber nicht zu jedem X-Wert ein eindeutiger Y-Wert. Will man dagegen zu einem X-Wert alle zugehörigen Y-Werte addieren, so lässt sich das relativ leicht ausdücken
Programm 5c:
X, Yl l
1    4 6
3    8 6
ext Z:=X + sum(L(Y)) at X
Ergebnis:
X, Z,  Yl l
1  11  4
       6
3  17  8
       6

Programm 6: näherungsweise Berechnung der ersten Ableitung
aus <L(X): -3.2 to 3.2 step 0.01>
ext DELTA := 0.0001
ext SINUS := X sin
ext DERIVATION := X+DELTA sin - (X sin) : DELTA
weg DELTA
Durch die erste Programmzeile entsteht eine einspaltige Tabelle von X-Werten. Durch DELTA:=0.0001 wird eine neue Spalte mit dem Namen DELTA und dem Wert 0.0001 erzeugt. Da der Term auf der rechten Seite die Spalte X nicht enthält und der at-Teil „at X“ nicht angegeben wurde, entsteht ein Tabment vom Typ „DELTA, Xl“, die den Wert für DELTA nur einmal enthält. Bei der Angabe „at X“ würde DELTA neben jedem X-Wert vorkommen. Durch die nächste Zeile wird jeder X-Wert in der Spalte SINUS um den entsprechenden Sinuswert erweitert. Es entsteht eine Tabelle vom Typ „DELTA, X, SINUS l“. Durch die nächste Erweiterung wird für jeden X-Wert der Differenzenquotient „DELTA_Y“ durch (:) „DELTA_X“ berechnet, weshalb ein Tabment vom Typ
„DELTA, X, SINUS, DERIVATION l“
entsteht. Da wir keine Umstrukturierung dieser Daten wünschen, sondern nur die Spalte DELTA streichen wollen, benötigen wir keinen gib-Teil. Im Allgemeinen kann man nach weg Spalten angeben, die man nicht mehr im Endergebnis benötigt. Unser Endergebnis umfasst 641 Sätze (Tripel) der folgenden Gestalt. Diese können auch bildlich dargestellt werden (image).
X,                 DERIVATION,        SINUS l
-3.2               -0.99829769284      0.0583741434276
-3.19              -0.998831010937     0.0483884433684
-3.18              -0.999264446765     0.0383979045052
-3.17              -0.99959795698      0.0284035258836
-3.16              -0.999831508234     0.0184063069331
...
3.19               -0.998826172092    -0.0483884433684
3.2                -0.998291855426    -0.0583741434275

4 Die Selektion

o++oPS wurde ursprünglich als Datenbankanfragesprache konzipiert. Dort und im Internet spielt die Selektion eine entscheidende Rolle. Ein Suchmaschinenanfrage (z.B.: ein "Google-Programm“) besteht in der Regel aus einem oder mehreren Worten (z.B. „Hadmersleben“). Als Ergebnis erhält man alle Dokumente, die dieses Wort enthalten. Das ist eine Teilmenge aller Dokumente des Internets. Die einfachsten SQL-Anfragen bestehen dagegen aus einem Spaltennamen, einem Relationszeichen und einem Wert (z.B. GEBURTSORT=“Hadmersleben“) .
In beiden Fällen werden die Anfragen effizient berechnet, da in der Regel entsprechende Indexe ausgenutzt werden und nicht die gesamten Dateien oder das gesamte Internet durchsucht werden.
Im allgemeinen wird eine Selektion durch einen mit-Teil beschrieben:
mit [name:] condition
Im Gegensatz zu anderen Sprachen kann eine Selektion mehrfach in einer Anfrage vorkommen. Selektionen in o++oPS verändern das Schema und die TTD des gegebenen Tabments nicht. Ein mit-Teil beginnt mit dem Schlüsselwort "mit", optional gefolgt von einem Level-Selector "name:", gefolgt von einer Bedingung, das ist ein BOOL-wertiger Ausdruck. Alle (Teil-) Elemente von Kollektionen, die den Namen als Komponente enthalten und die die  Bedingung nicht erfüllen, werden vom Tabment gestrichen.
Da unsere Daten komplexer strukturiert sind, besitzen wir feinere Selektionsmechanismen als das flache relationale Datenmodell. Wir haben aber dennoch eine einfache Syntax (Schreibweise). Die TTD von schuelers.xml enthält drei Kollektionssymbole, daher können wir in drei verschiedenen Ebenen selektieren.
SCHUELER! NAME=Mayer
selektiert Schüler
FACHTUP! NOTE=3
selektiert FACHTUP-Elemente aller Schüler (alle in denen eine 3 existiert) und
NOTE! NOTE>3
selektiert Noten.
Da wir SCHUELER oder FACHTUP-Elemente auch selektieren wollen, wenn kein SCHUELER- oder FACHTUP-Tag vorhanden ist, müssen wir die Syntax (Schreibweise) etwas erweitern. Vor „:“ lassen wir deswegen auch einfache Spaltennamen zu.
NAME! NAME=Mayer und VORNAME! NAME=Mayer drücken daher das Gleiche aus wie die erste Bedingung. Diese Bedingungen selektieren daher ebenfalls Schüler.
Programm 7:
aus schuelers.xml
avec NAME! FACH=Chemie
selektiert daher in der Menge der Schüler und nicht in der Menge der FACHTUP-Elemente. Allerdings verschwinden mit einem Schüler natürlich auch alle seine untergeordneten Fächer und Noten. Somit erhalten wir folgendes Ergebnis:
NAME,   VORNAME,  (FACH,   NOTEl l)l
Schulz  Michael    Chemie  1 4 4 4 4 4 4 4 4 4
                   Deutsch 1 4
Schmidt Max        Mathe   1 4 2 1 4 2 1 4 2
                   Chemie  4
Wir erkennen, dass durch die Bedingung alle Schüler, die einen Chemieeintrag besitzen herausgefiltert werden, wobei allerdings alle Fächer dieser Schüler ausgegeben werden. Interessieren wir uns nur für die Chemieeinträge aller Schüler, so lässt sich das auch leicht ausdrücken:
Programm 8:
aus schuelers.xml
avec FACH! FACH=Chemie
Ergebnis:
NAME,   VORNAME,       (FACH,  NOTEl l) l
Meier   Hans Peter Paul
Mueller Antje
Schulz  Michael         Chemie  1 4 4 4 4 4 4 4 4 4
Schulz  Michael
Schmidt Max             Chemie  4
Mayer   Fritz
Chang   Lee
Perner  Nadin
Mayer   Fritz
Wenden wir beide Bedingungen hintereinander an, so erhalten wir alle Chemieeinträge, aber auch nur die Schüler die Chemieeinträge besitzen:
Programm 9:
aus schuelers.xml
avec NAME! FACH=Chemie
avec FACH! FACH=Chemie
Ergebnis:
NAME,   VORNAME,  (FACH,   NOTEl l)l
Schulz  Michael    Chemie  1 4 4 4 4 4 4 4 4 4
Schmidt Max        Chemie  4
Man kann beide Bedingungen auch durch
aus schuelers.xml
avec FACH! FACH=Chemie
avec NAME! FACHm != {}
oder
aus schuelers.xml
avec FACH=Chemie
ersetzen.
Betrachtet man die Bedingung NOTE=3, so kann man mit dieser Bedingung gleich in drei Kollektionstypen selektieren. Anstelle dieser 3 Bedingungen
avec NAME! NOTE=3  # Schüler mit einer 3
avec FACH! NOTE=3  # Fächer  mit einer 3
avec NOTE! NOTE=3
werden wir folgende Kurzform verwenden:
Programm 10:
aus schuelers.xml
avec NOTE=3

Ergebnis:
NAME,  VORNAME,   (FACH,    NOTEl l)l
Mayer  Fritz       Mathe    3 3 3 3 3
avec NOTE=3
drückt aus, dass die Bedingung NOTE=3 auf alle Kollektionen, die höher liegen als das tiefste Feld der Bedingung (hier NOTE) angewandt wird. Damit ist sie gleichwertig zu obigen drei Bedingungen.
Programm 11:
schuelers.xml
sans NAME! NOTE=4
Es erscheinen im Ergebnis nur Schüler (mit all ihren Daten), die in keinem Fach eine 4 haben.
Ergebnis:
NAME,  VORNAME,       (FACH,   NOTEl l)l::
Meier  Hans Peter Paul Mathe   1 1 1
Mayer  Fritz           Mathe   3 1 3 1 3 1 3 1 3 1
                       Physik  2
Chang  Lee             Mathe   2 2 1
Perner Nadin           Deutsch 1
                       Mathe
Mayer  Fritz
Als nächste wollen wir die einfache Anfrage „Wie viele Einsen wurde bisher insgesamt vergeben?", betrachten. Wir wissen bereits, dass man mit dem gib-Teil auch Aggregationen (z.B. count) durchführen kann.
Programm 12 a:
aus schuelers.xml
avec NOTE! NOTE=1
gib ANZ ANZ:=cnt NOTE
Programm 12 b:
aus schuelers.xml
gib ANZ
    ANZ:=cnt NOTE=1 dann1 NOTE

Programm 12 c:
aus schuelers.xml
avec NOTE! NOTE=1
cnt NOTE
In allen 3 Fällen ergibt sich:
26

Es können auch Operationen zu Beginn einer Zeile geschrieben werden.
Programm 13:
2+8
*5+9
Ergebnis:
140
Programm 14:
2+8*5+9
Ergebnis:
59
In Programm 13 wird das Ergebnis der ersten Zeile mit dem Ergebnis des zweiten Arguments von "*" (5+9) multipliziert.