Język skryptów SowaSQL

Język skryptów SowaSQL

Język skryptów SowaSQL jest wykorzystywany w wielu różnych miejscach systemu. Pozwala na algorytmiczne wyrażenie dowolnego procesu przetwarzania zawartości rekordu. Wynik procesu przetwarzania jest zawsze napisem (zorganizowanym w wiersze), który jest następnie interpretowany przez jeden z elementów systemu:

  1. program wyświetlania rekordu (klient SOWA-TCP lub WWW) [*.vpr]

  2. program sortowania kolekcji [*.spr, *.vpr]

  3. program prezentacji rekordu w zestawieniu [*.zpr]

  4. program aktualizacji rekordu (przed i po zakończeniu edycji) [*.apr]

  5. program aktualizacji rekordu po akcji edycyjnej pola (wejście, wyjście) [*.act]

  6. program operacji na bazie danych [*.ppr]

Język skryptów składnią przypomina typowe języki programowania. Jedynym typem danych dostępnym w tym języku są łańcuchy znaków. Napisy zapisywane są w apostrofach. Pojedyncze znaki można zapisać w postaci \kod i bez żadnych operatorów połączyć z resztą łańcucha w apostrofach. Przykład stałej łańcuchowej:

'Początek'\27'CG'\26'Test'

 

Podstawowe instrukcje języka skryptów

Struktura każdego programu ma postać:

Przykład deklaracji procedury i programu głównego
procedure nazwa1 begin lista_instrukcji end ... begin lista_instrukcji end

Poszczególne elementy lista_instrukcji są separowane spacją lub zmianą wiersza; nie ma żadnego widocznego znaku separatora.

Instrukcja

Interpretacja

Instrukcja

Interpretacja

PRINT(wartość)

dopisuje wartość do listy wyników programu.

TRACE(wartość)

służy do wyprowadzenia wartości dla celów testowych. Wartość pojawi się w pliku dziennika serwera albo w oknie programu klienta (zależnie od przeznaczenia skryptu)

zmienna=wartość

Instrukcja podstawienia. Pierwsze wywołanie instrukcji podstawienia tworzy zmienną. Wszystkie zmienne w ramach jednego programu są globalne (tzn. zmienna ustawiona w programie głównym jest dostępna w procedurze i na odwrót). Nazwa zmiennej jest dowolnym ciągiem liter i znaków '_'. Może także zawierać cyfry, ale nie może się od cyfry rozpoczynać. Wielkość znaków nie ma znaczenia.

{napis}

Komentarz.

// napis

Komentarz do końca linii

IF wartość
   lista_instrukcji
ELSE
   lista_instrukcji
ENDIF

Instrukcja warunkowa. Jeżeli wartość jest pustym napisem, to wykonywana jest pierwsza lista_instrukcji, w przeciwnym przypadku - druga. Fragment ELSE lista_instrukcji jest opcjonalny.

WHILE
   lista_instrukcji
ENDDO

Instrukcja pętli. Lista_instrukcji jest wykonywana tak długo jak wartość jest pustym napisem.

Jeśli zdefiniowano procedury (podprogramy), można je wywołać w programie głównym wywołując nazwę procedury w liście instrukcji.

Nawigacja w rekordzie logicznym SowaSQL

Pola w rekordzie logicznym SowaSQL mogą tworzyć strukturę hierarchiczną, maksymalnie 5-poziomową. O sposobie umieszczenia pola w hierarchii decydują dwa elementy:

  • oznaczenie pola,

  • indeks wystąpienia pola.

Oznaczenie pola jest ciągiem maksymalnie 5 znaków, z których każdy identyfikuje grupę pól na kolejnym poziomie hierarchii. Nazwy pól mogą składać się z dowolnych znaków, przy czym rozróżniane są małe i wielkie litery. Każdy kolejny znak nazwy pola określa przynależność pola do odpowiedniej ścieżki hierarchii. Przykładowo pola AA i AB w tak rozumianej hierarchii należą do wspólnej grupy A. Lista nazw pól jest ustalona dla danego katalogu. Listę określa plik katalog.ini definiujący strukturę katalogu.

Przykład 1.

Struktura pól reprezentujących listę autorów i tytuły może mieć postać:

A {grupa reprezentująca oznaczenie odpowiedzialności} AN {pole nazwisko (nazwiska) osoby} AI {pole imię (imiona) osoby} AF {podgrupa reprezentująca rolę osoby} T {grupa reprezentująca tytuły} TR {pole rodzaju tytułu} TT {pole tytułu}


Indeks wystąpienia pola jest ciągiem oddzielonych kropkami liczb, określających położenie pola w poszczególnych poziomach hierarchii. Przykładowo pola AB.1.1 i AB.1.2 są podporządkowane polu A.1, natomiast pole AB.2.1 polu A.2. Pola A.1 i A.2 leżą na jednym (najwyższym) poziomie.

Przykład 2.

Przykładowy rekord zawierający informacje o dwóch autorach może mieć postać:

AN .1.1=Kowalski AI .1.1=Jan AI .1.2=Andrzej AF .1.1=autor AN .2.1=Jasnorzewska AN .2.2=Pawlikowska AI .2.1=Krystyna AF .2.1=red.

Rekord SowaSQL jest widziany przez programistę raczej jako drzewo niż lista pól. Dlatego w językach skryptowych należy stosować polecenia umożliwiające poruszanie się po tak rozumianym drzewie. Wartość bieżącego pola reprezentowana jest zmienną standardową POLE. Jeżeli bieżącego pola nie ma w rekordzie, to wartością zmiennej POLE jest pusty łańcuch (''). Bieżący indeks wystąpienia reprezentowany jest zmienną standardową POZYCJA.

W chwili startu programu skryptu nazwa bieżącego pola i wystąpienie są puste. Do nawigacji w rekordzie służą instrukcje:

Instrukcja

Interpretacja

Instrukcja

Interpretacja

GRUPA(nazwa)

W wyniku tej operacji atrybuty bieżącego pola zostają umieszczone na stosie. Następnie do nazwy bieżącego pola zostaje dodany parametr nazwa, i zostaje wyszukane pierwsze pole z wystąpieniem pasującym do bieżącego (czyli pierwsze w poddrzewie). Wystąpienie tego pola staje się wystąpieniem bieżącym. W wyniku operacji nadawana jest wartość zmiennej standardowej OK. Jeśli rekord nie zawiera bieżącego pola, to zmienna OK staje się równa 'N', w przeciwnym przypadku jej wartością jest pusty łańcuch ('').

SKIP

W wyniku tej operacji bieżącym staje się pole następne na tym samym poziomie. Jeśli nie ma takiego pola, to zmienna standardowa OK staje się równa 'N', w przeciwnym przypadku jej wartością jest pusty łańcuch.

POZYCJA=wystąpienie

Instrukcja ustawia bieżące wystąpienie na podaną wartość (nie ma znaczenia czy pole istnieje czy nie). Wartością wystąpienie jest łańcuch zawierający pełny ciąg oddzielonych kropkami liczb dla pola w bieżącym miejscu hierarchii. Np. jeśl bieżącym polem jest AN, wówczas ustawienie pozycji na drugie wystąpienie pola N (na nazwisko Pawlikowska z przykładu 2) odbywa się przez przypisanie POZYCJA='.2.2'

BACK

Odtwarza pole bieżące ze stosu (powrót do stanu sprzed instrukcji GRUPA lub OPEN)

OPEN(rekord)

Przechodzi do wskazanego rekordu SowaSQL. Zazwyczaj skrypt uruchamiany jest już dla otwartego wcześniej rekordu - tym poleceniem można w obrębie skryptu czasowo przełączyć przetwarzanie na inny rekord.

Przykład 3. Algorytm przechodzący przez wszystkie wypełnione pola z przykładu 2 wygląda następująco:

GRUPA('A') {pętla po kolejnych autorach} while OK {nazwisko (nazwiska)} GRUPA('N') while OK {...} SKIP enddo BACK {imię (imiona)} GRUPA('I') while OK {...} SKIP enddo BACK {funkcja autora} GRUPA('F') while OK {...} SKIP enddo BACK {przechodzimy do kolejnego autora} SKIP enddo BACK

Wyrażenia

Wyrażenia w języku skryptów pozwalają użyć prostych operacji na łańcuchach. Wyrażenia mogą mieć postać:

Wyrażenie

Opis

Wyrażenie

Opis

! wyrażenie

jeśli wartość wyrażenie jest pustym napisem to wynikiem jest 'N', w przeciwnym przypadku '' (pusty łańcuch)

wyrażenie1 + wyrażenie2

konkatenacja dwóch łańcuchów

wyrażenie1 = wyrażenie2

jeśli wartości wyrażenie1 i wyrażenie2 są identyczne, to wynikiem jest '' (pusty łańcuch), w przeciwnym przypadku 'N'

wyrażenie1 wyrażenie2

jeśli wartości wyrażenie1 i wyrażenie2 są różne, to wynikiem jest '' (pusty łańcuch), w przeciwnym przypadku 'N'

wyrażenie1 or wyrażenie2

wynikiem jest '' (pusty łańcuch) tylko wtedy gdy wartość przynajmniej jednego z wyrażeń jest pustym napisem, w przeciwnym przypadku wynikiem jest 'N'

wyrażenie1 > wyrażenie2

jeśli wyrażenie1 jest alfabetycznie większe od wyrażenie2, to wynikiem jest '' (pusty łańcuch), w przeciwnym przypadku 'N'. Stosowany jest polski alfabet (z uwzględnieniem znaków diakrytycznych)

Wyrażeniem jest także nazwa zmiennej (w tym także zmiennej standardowej).

Funkcje i zmienne standardowe

Zmienne standardowe, to zarezerwowane nazwy zmiennych mające specjalne przeznaczenie.

Nazwa zmiennej

Odczyt zmiennej

Zapis zmiennej

Nazwa zmiennej

Odczyt zmiennej

Zapis zmiennej

OK

Wynik poprzedniej operacji GRUPA() lub SKIP. Wartość 'N' oznacza brak grupy lub kolejnego wystąpienia w rekordzie. W przeciwnym razie wartość jest pusta ('')

Tylko do odczytu

POLE

Pobiera wartość bieżącego pola.

Ustawia nową wartość bieżącego pola (tylko w programach APR, PPR i ACT)

PIERWOTNE

Pobiera początkową wartość bieżącego pola (przed ew. modyfikacją).

Tylko do odczytu

POZYCJA

Pobiera bieżący indeks wystąpienia.

Zob. "Nawigacja w rekordzie logicznym SowaSQL"

REKORD

Numer bieżącego rekordu SOWA-2

Tylko do odczytu

HEADER

Parametr przekazywany przy wywołaniu skryptu

Zmienia wartość zmiennej.

LP

Zmienna globalna, zachowująca swoją wartość przy kolejnych wywołaniach skryptu (wycofywana)

 

EDYTOWALNE

Znacznik edytowalności bieżącego pola (dotyczy tylko skryptów ACT i APR).

Ustawienie wartości EDYTOWALNE='N' zablokuje możliwość edycji bieżącego pola na formularzu

Funkcje operują zawsze na łańcuch znaków i ich wynikiem jest także łańcuch znaków.

Nazwa i parametry funkcji

Opis

Przykłady / uwagi

Nazwa i parametry funkcji

Opis

Przykłady / uwagi

head(s1, s2)

Zwraca fragment łańcucha s1 poprzedzający s2. Jeśli s1 nie zawiera s2, zwracany jest pusty łańcuch.

 

tail(s1, s2)

Zwraca fragment łańcucha s1 następujący po s2. Jeśli s1 nie zawiera s2, zwracany jest cały łańcuch s1.

 

sep(s1, s2, s3)

Łączy łańcuchy s1 i s3 separatorem s2, o ile s1 i s3 są niepustymi łańcuchami. Jeśli jeden z łańcuchów s1 lub s3 jest pusty, zwracany jest tylko drugi, niepusty łańcuch.

 

reverse(s)

Przestawia pierwszy wyraz na koniec. Jako miejsce podziału w pierwszej kolejności przyjmowany jest pierwszy napotkany przecinek. Jeśli nie ma przecinka, miejscem podziału jest pierwsza spacjia.

Warunek specjalny: jeśli s kończy się sekwencją [wartość] - wówczas jest ona zachowywana na miejscu, przestawienie wyrazu dotyczy części łańcucha poprzedzającej tą sekwencję.

 

up(s)

Zamienia wszystkie litery s na wielkie.

 

lo(s)

Zamienia wszystkie litery s na małe.

 

matches(s, pattern)

Sprawdza czy łańcuch s pasuje do wzorca pattern i jeśli tak, zwracany jest pusty łańcuch. Jeśli nie, zwraca wartość 'N'. W składni wzorca występują dwa znaki specjalne:

? - zastępuje dowolny pojedynczy znak
* - zastępuje dowolny ciąg znaków

 

position(substr, s)

Sprawdza czy łańcuch s zawiera łańcuch substr. Jeśli tak, zwracana jest pozycja substr w łańcuchu s (indeksy znaków liczone od 1). Jeśli nie, zwracany jest pusty łańcuch.

 

succ(n)

Dodaje 1 do wartości liczbowej wyrażonej w łańcuchu n (zwraca n+1). Jeśli n nie jest liczbą, zwracane jest '0'.

 

add(n1, n2)

Dodaje dwie wartości liczbowe wyrażone w łańcuchach n1 i n2 (zwraca n1+n2). Jeśli n1 lub n2 nie jest liczbą, traktowany jest jako '0'.

 

mul(n1, n2)

Mnoży dwie wartości liczbowe wyrażone w łańcuchach n1 i n2 (zwraca n1*n2). Jeśli n1 lub n2 nie jest liczbą, zwracana jest wartość '0'.

 

div(n1, n2, digits)

Dzieli dwie wartości liczbowe wyrażone w łańcuchach n1 i n2 (operacja n1/n2). W wartości liczbowej wyrażonej w łańcuchu digits określić należy liczbę zwracanych miejsc po przecinku. Jeśli dowolna z wartości nie jest liczbą, albo n2 jest zerem, zwracana jest wartość '-' (minus). Jeśli digits jest liczbą większą od zera, separatorem części ułamkowej jest przecinek.

 

gt(n1, n2)

Porównuje dwie wartości liczbowe wyrażone w łańcuchach n1 i n2. Jeśli n1 lub n2 nie jest liczbą, traktowany jest jako '0'. Jeśli n1 jest większy od n2, zwracany jest pusty łańcuch. W przeciwnym razie zwracana jest 'N'.

 

ge(n1, n2)

Porównuje dwie wartości liczbowe wyrażone w łańcuchach n1 i n2. Jeśli n1 lub n2 nie jest liczbą, traktowany jest jako '0'. Jeśli n1 jest większy lub równy n2, zwracany jest pusty łańcuch. W przeciwnym razie zwracana jest 'N'.

 

replace(line, s1, s2)

Zastępuje w line wszystkie wystąpienia s1 wartością s2.

 

trim(s)

Obustronnie usuwa spacje z wartości s.

 

sort(list, sep)

Sortuje alfabetycznie listę wyrażoną w łańcuchu list, przy założeniu że elementy listy wyznaczone są separatorem sep. Stosowany jest alfabet polski (z uwzględnieniem znaków diakrytycznych')

Np. sort('Książka|Film|Muzyka|','|') = 'Film|Książka|Muzyka|')

agregate(line, sep)

Agreguje listę kolejnych identyfikatorów w lini do postaci "od - do" (uprzednio je sortując). Identyfikatory rozdzielane są separatorem sep.

Np. agregate('1|2|3|4|5|', '|') = '1-5|'
agregate('1|2|3|5|, '|') = '1-3|5|'

ord(s)

Zwraca kod ASCII pierwszego znaku łańcucha s.

 

chr(n)

Zwraca znak o kodzie ASCII wyrażonym w łańcuchu n.

 

random(n)

Zwraca liczbę losową w przedziale od 0 do wartości liczbowej wyrażonej w łańcuchu n.

 

omit(s)

Zwraca łańcuch z pominięciem znaczników podpól MARC-21. Oznaczenie znacznika podpola zależy od konfiguracji, zwykle jest to ^c gdzie c to znak podpola.

 

subfield(line, c)

Zwraca wartość podpola c w wierszu line, zawierającym pole MARC-21 z oznaczeniami podpól. Jeśli line nie zawiera podpola o kodzie c, zwracany jest pusty łańcuch.

Np. subfield('^aDziady ^cMickiwicz', 'a') = 'Dziady '

marker(line)

Zwraca oznaczenie pierwszego podpola w line, zawierającym pole MARC-21 z oznaczeniami podpól.

Np. marker('^aDziady ^cMickiwicz') = 'a'

mak(line)

Zamienia symbole liter obcych alfabetów MAK na zwykłe

 

uri(s)

Koduje znaki specjalne w łańcuch s, do postaci zgodnej z formatem URI (adresy zasobów w HTTP)

 

utf8(s)

Koduje łańcuch s do postaci w UTF-8.

 

pr(sep, line)

Jeśli łańcuch line jest niepusty, zwraca line poprzedzony wartością sep.

 

ta(line, sep)

Jeśli łańcuch line jest niepusty, zwraca line+sep.

 

form(s, pattern)

Formatuje łańcuch s wg wzorca pattern. Przetwarzane są kolejne znaki łańcucha s wg odpowiadającym ich pozycji znakom z wzorcu pattern. Wzorzec może zawierać znaki 'A' - przepisanie znaku z łańcucha s, oraz '\' (backslash) - pominięcie znaku z łańcucha s. Inne znaki ze wzorca są bezpośrednio przepisywane do wyniku.

Np. form('2012-10-20', '\\\\\AA') = '10'
form('123', 'A-A-A') = '1-2-3'

rform(s, pattern)

Formatuje łańcuch s wg wzorca pattern, przy czym w odróżnieniu od funkcji form -  łańcuch s przed rozpoczęciem formatowania jest odwracany (przetwarzanie s odbywa się od końca).

Np. rform('2012-10-20', '\\\AA') = '10'

date(n)

Zwraca bieżącą datę powiększoną o n dni w formacie RRRRMMDD. Jeśli n jest pustym łańcuchem zwracana jest bieżąca data.

Np. w dniu 2012-10-20: date(2) = '20121022'

time(n)

Zwraca bieżący czas powiększony o n sekund w formacie GGMMSS. Jeśli n jest pustym łańcuchem zwracany jest bieżący czas.

Np. o godzinie 12:23:02: time(70) = '122412'

days(d1,d2)

Zwraca liczbę dni między datą d1 i d2. Daty powinny być wyrażone w postaci RRRRMMDD, a d2 być datą późniejszą od d1.

 

cfg(name)

Zwraca parametr katalogu o nazwie name

 

external(line)

Wywołuje niestandardową metodę zdefiniowaną w zewnętrznym module serwera aplikacji lub programie klienta (zob. dalej).

 

first(idf, prefix)

Wartość pierwszego wpisu w indeksie idf+prefix.

 

next(idf, prefix, key)

Wartość następnego wpisu w indeksie idf+prefix, za key (key musi istnieć i jest kontrolowane z uwzględnieniem małych i wielkich liter)

 

find(idf, key)

Znajduje wartość najbliższego wpisu w indeksie idf, począwszy od key (ignorowana jest wielkość liter)

 

last(idf, prefix)

Wartość ostatniego wpisu w indeksie idf+prefix

 

select(record, hard, pattern)

Zwraca listę numerów rekordów, separowanych '|', dla których klucz indeksu jest zgodny z hard i spełnia pattern.

 

references(id)

Zwraca listę numerów rekordów, separowanych '|', które zawierają referencję do id.

 

 

Implementacja rekordu MARC-21 w rekordzie logicznym SowaSQL

Dla rekordów MARC-21 przyjęto następujący model reprezentacji:

Element rekordu MARC21

Reprezentacja w SowaSQL

Uwagi

Element rekordu MARC21

Reprezentacja w SowaSQL

Uwagi

Leader

L.1

 

Wskaźnik nr 1 pola xxx

xxxA.1.1.*.1

* oznacza numer kolejnego wystąpienia pola MARC21

Wskaźnik nr 2 pola xxx

xxxB.1.1.*.1

 

Treść pola xxx

xxxZ.1.1.*.1

 

Wskaźniki oraz treść 001Z, 005Z przechowywane są w polach indeksowanych, natomiast pozostałe elementy w polach nieindeksowanych. W związku z tym system SowaSQL dla każdego rekordu MARC-21 wyznacza dodatkowe pola, które reprezentowane są jako indeksowane. Zawartość tych pól decyduje o budowie poszczególnych indeksów umożliwiających wyszukiwanie danych. Sposób wyliczenia tych pól określa skrypt wykonywany każdorazowo przy zamknięciu rekordu.

W typowym katalogu MARC-21 przechowywane są rekordy bibliograficzne (oznaczone U), rekordy wzorcowe haseł przedmiotowych (oznaczone A) oraz rekordy wzorcowe haseł formalnych (oznaczone C).