Table of Contents

External Hooks in MetaLib

1. Einleitung

MetaLib ist eine enorm vielseitige Portalsoftware für Informationsquellen aller Art, von Bibliothekskatalogen, über Z39.50-Server bis hin zu Inhalten entfernter WWW-Server. Sie besticht vor Allem durch die Möglichkeit, diese unterschiedlichen Datenquellen unter einer einheitlichen Oberfläche verfügbar zu machen. Dieses Prinzip einer virtuellen Bibliothek macht es für den Benutzer einfach, die für ihn relevantesten Informationen aus verschiedenen Medienarten zu aggregieren, indem MetaLib ihm die Freiheit gibt, durch Auswahl der gewünschten Datenbanken eine auf den Benutzer zugeschnittene Metasuche durchzuführen. Mit den Möglichkeiten der digitalen Authentifizierung über Dienste wie SFX / OpenURL kann im Idealfall direkt auf die gefundenen, digitalen Dokumente zugegriffen werden oder, wenn das nicht möglich ist, können sie in gedruckter Form ausgeliehen werden. All dies und noch mehr ist möglich, ohne die Benutzeroberfläche von MetaLib verlassen zu müssen.
Für Bibliothekare ist die Software durch ihre Modularität von besonderem Interesse. Mit genügend Kenntnissen in einer Programmiersprache und der MetaLibsoftware ist es möglich, beliebige Datenquellen in die Oberfläche einzubinden. Wie das im Einzelnen funktioniert, soll in dieser Arbeit geklärt werden.
Zunächst soll in dieser Arbeit die grundlegende Vorgehensweise beim Erstellen solcher skriptbasierter Erweiterungen erläutert werden. Danach wird dargestellt, wie das System der 'External Hooks', also der programmierbaren Suchdienste in MetaLib, funktioniert. Schließlich wird am Beispiel des Hooks zum bibliotheks- und informationswissenschaftlichen Open Access Repository E-LIS praktisch gezeigt und erläutert, wie eine solche Erweiterung im Quelltext konkret aussehen kann. Durch die ganze Arbeit hindurch werden die Beispiele der Hooks für E-LIS und den del.icio.us Account des Instituts für Bibliotheks- und Informationswissenschaften Berlin bestimmend sein, denn diese waren die zentrale Aufgabe dieses Teils der Arbeitsgruppe innerhalb des Projekts.

2. Vorgehensweise

Wann immer für bestehende Software im Rahmen einer API [1] externe Skripte erstellt werden sollen, die die Funktionaliät um die Einbindung von Daten von Drittanbietern erweitern, gibt es Ähnlichkeiten in der Vorgehensweise - unabhängig davon, ob es sich um einen External Hook für MetaLib, eine Extension für Firefox oder ein Plugin für ein Content Management System handelt. Im Wesentlichen läßt sich der Handlungsablauf in zwei Bereiche einteilen, Analyse und Umsetzung, wobei sich die Analyse sowohl auf bereits existierende Skripte als Vorlagen, als auch auf die zu verarbeitenden Daten erstrecken muss. Die Umsetzung sollte selbstverständlich auch gut geplant und von vornherein durchdacht sein. Allerdings ist die Erstellung solcher Erweiterungen, wenigstens beim ersten Kennenlernen einer neuen Software und ihrer Schnittstellen, ein typischer Fall für die "Ninety-Ninety-Rule" [2], d.h. der Quelltext scheint zu 90% fertig programmiert zu sein, aber die letzte Phase des Debuggens und Testens nimmt dann noch einmal genauso viel Zeit in Anspruch wie der gesamte Entwicklungsprozess bis dahin. Insofern ist es wichtiger, zu wissen, wie man effiziente Tests durchführen und wo man Fehlermeldungen finden kann, als das Programm selbst so elegant wie möglich zu schreiben. Das gilt umso mehr, als sich in Perl, der verwendeten Programmiersprache, viele Abläufe so verkürzt und kryptisch ausdrücken lassen, dass man mitunter innerhalb kürzester Zeit den Quelltext der eigenen Programme nicht mehr versteht. Insofern wird in dieser Arbeit mehr Gewicht auf Transparenz und Nachvollziehbarkeit, als auf Effizienz gelegt.

2. 1. Analyse bestehender Skripte

MetaLib ist bei vielen, großen Bibliotheken weltweit im Einsatz, darunter sehr viele Universitätsbibliotheken in den USA und Großbritannien, aber auch beim KOBV und dem Bibliotheksverbund Bayern wird die Software genutzt. Dementsprechend finden sich "ab Werk" bereits viele External Hooks in der sog. Knowledge Base und können ohne jeden Aufwand eingebunden werden. Für Internetquellen, für die in der Knowledge Base noch keine Skripte zu finden sind, hat aber vielleicht bereits jemand einen External Hook geschrieben. In jedem Fall lohnt es sich, einen Blick in die Skripte anderer MetaLibanwender zu werfen. Ein kurzes Durcharbeiten der vorhandenen Skripte klärt bereits Grundlegendes:

Aus diesen einfachen Beobachtungen heraus wird deutlich, wie ein External Hook funktioniert: MetaLib schickt die Benutzereingaben an das find-Skript, MetaLib zeigt die Trefferanzahl und startet das present-Skript, dem es die URL aus dem find-Skript übergibt. Schließlich parst das present-Skript den HTML-Quelltext der externen Seite und MetaLib gibt die Daten formatiert aus. Das ist natürlich vereinfacht (siehe 3. für eine genauere Erklärung), aber im Großen und Ganzen ist das der ganze Vorgang. Ob es sich aber tatächlich um HTML handelt oder ein anderes Datenformat, in dem die Daten der externen Quelle vorliegen, wird erst durch Analyse derselben ersichtlich.

2. 2. Analyse der vorliegenden Daten

Dass die External Hooks für MetaLib ausnahmslos in Perl geschrieben sind, mag zu einem Großteil der weiten Verbreitung der Sprache auf unixoiden Systemen geschuldet sein, ist aber auch sehr naheliegend, den Perl (häufig abgekürzt als Practical Extraction and Report Language) ist ideal geeignet, um strukturierte Textdateien auszulesen und zu verarbeiten. Hat man erst einmal die Strukur einer textuellen Datensammlung erkannt, lässt sich der Analyse- und Verarbeitungsvorgang in Perl meist in wenigen Zeilen schreiben. Die meisten Daten, die über das WWW zugänglich sind, liegen in einer XML-artigen Form (HTML) oder reinem XML (XHTML) vor und es liegt in der Natur von XML, dass es problemlos zu parsen ist. Ein Absatz in einer XML-Datei, der bspw. folgendes Schema aufweist, ist fast wörtlich in Perl umsetzbar:
<book>
  <title>Freiheit Pur</title>
  <author>Horst Stowasser</author>
  <fulltext_url>http://www.mama-anarchija.net/media/downloads/FreiheitPur.pdf</fulltext_url>
</book>

Ähnlich verhält es sich, wenn die Daten in sauber gekapseltem XHTML vorliegen. Das Beispiel bleibt im Wesentlichen das Gleiche, nur dass dieses in einem mikroformat-artigen [3], XHTML-konformen Format vorliegt:

<div class="book">
  <span class="book_title">Freiheit Pur</span>
  <span class="book_author">Horst Stowasser</span>
  <a href="http://www.mama-anarchija.net/media/downloads/FreiheitPur.pdf" class="book_url">zum Volltext</span>
</div>

Es ist allerdings zu beachten, dass HTML-Seiten für Menschen und nicht für Maschinen (d.h. Skripte) gemacht werden und deshalb nur selten so einfach und sauber strukturiert sind wie im vorgenannten Beispiel. Deshalb sollte man, wenn man auf die Daten mit einem Skript zugreifen will, nach Möglichkeit ein maschinenlesbares Format wählen. Viele Webapplikationen bieten im Rahmen ihrer API Datenformate an, die weniger Overhead produzieren und einfacher zu parsen sind. Ein solches Format, das bspw. bei del.icio.us eingesetzt wird, ist JSON (JavaScript Object Notation). Dieser Standard reduziert durch eine minimalistische Syntax den beim Datenaustausch verursachten Overhead auf ein Minimum. Die JSON-Repräsentation eines Bookmarks bei del.icio.us sieht so aus:

{
  "u":"http://www.ib.hu-berlin.de/studium/praktikum/bibliothekspraktika.htm",
  "n":"Liste von Einrichtungen, in denen Studenten des IB der HU schon Praktika gemacht haben.."
  "d":"Einrichtungen Bibliothekspraktikum",
  "t":[
    "ausbildung",
    "bibliothekswissenschaft",
    "informationswissenschaft",
    "praktikum",
    "linkliste"
    ]
}

Die geschweiften Klammern umschließen ein Objekt, alle Bezeichner, die links der Doppelpunkte stehen, sind Variablennamen, alles, was rechts der Doppelpunkte liegt, sind Variablen, die eckigen Klammern umschließen Elemente eines Arrays. In dieser Form sind die Daten optimal weiterzuverarbeiten. Jeder Datensatz läßt sich in einem einzigen, guten regulären Ausdruck auswerten.
Die drei genannten Beispiele verdeutlichen, wie wichtig semantisches Markup ist. Um eine Webseite effektiv auszuwerten muss entweder der Quelltext formal und in seinen Bezeichnern einheitlich und standardkonform sein oder die Daten der Seite auch noch in einer anderen Inkarnation, etwa als JSON-String oder XML vorliegen. Die reine Ausrichtung an Formalia, z.B. an der Tabellenstruktur einer Seite,macht die Programmierung mühselig und fehleranfällig.

Nachdem nun bestehende Skripte durchgearbeitet und die auszuwertenden Daten in ihrer Struktur analysiert wurden, fehlt nur noch die Umsetzung in Programmcode.

2. 3. Umsetzung

Die gesamte Kommunikation zwischen MetaLib und Skripten spielt sich auf der Standardein- (STDIN) und -ausgabe (STDOUT) ab, daher lässt sich das gewünschte Verhalten des Skriptes leicht simulieren und gibt zugleich den Rahmen für den Aufbau sowohl des find-, als auch des present-Skripts vor:

  1. Einlesen der Standardeingabe
  2. Kommunikation mit der externen Seite
  3. Umwandlung/Formatierung der Daten
  4. Ausgabe über die Standardausgabe


Außerdem bietet sich die Nutzung der Standardausgabe (STDERR) an. Alle Daten die dorthin geschrieben werden, lassen sich in der Logdatei des Webservers (s.u.) wiederfinden und können während der Debugging-Phase sehr nützlich sein.
Da die offizielle Dokumentation zur Erstellung externer Suchskripte nur sehr sporadisch vorhanden ist [4], ist es in jedem Fall ratsam, bei der Integration der Skripte in die MetaLib-Software die Logdateien des Webservers (zu finden unter /exlibris/metalib/m3_3/log) mitzuverfolgen. Am günstigsten ist es, zwei Konsolenfenster mit Verbindung zum Server, auf dem MetaLib läuft, offenzuhalten. Im einen Terminal kann man dann die Skripte bearbeiten (am besten mit vi) und testen, im anderen mittels tail -f zeitnah die Ergebnisse in den entsprechenden Logdateien (insbesondere z39_gate_7333.log) beobachten.
Die Weboberfäche gibt für Entwickler keinerlei Informationen über etwaige Fehler aus, entweder es funktioniert oder nicht, daher sollte mit erhöhter Sorgfalt die Funktionalität der Skripte auch mit ungewöhnlichen Eingaben auf der Kommandozeile getestet werden. Hierbei ist insbesondere der verwendete Zeichensatz der verschiedenen Instanzen, durch die die Daten fließen, zu beachten. MetaLib bietet volle Unicode-Unterstützung, aber nicht alle externen Resourcen. Gerade bei Umlauten, Ligaturen oder Währungssymbolen kann es sonst zu kaum nachvollziehbaren Laufzeitfehlern kommen.
Abschließend sollte noch auf die Möglichkeiten der Automatisierung über Pipes in unixoiden Betriebssystemen hingewiesen werden. Um nicht jedes Mal beim Testen der Skripte die Befehle eingeben zu müssen, können die Tastatureingaben in eine Datei geschrieben und an die Skripte übergeben werden. Für ein Skript l_huib_delicious_find [5] kann man die Testanfrage [6]

FIND-REQUEST=WRD=(bibliothek) 

in eine Datei test_find schreiben und diese mit dem Befehl

  cat test_find | ./l_huib_delicious_find

an das Skript übergeben. Analog kann man auch eine Testanfrage für das present-Skript übergeben oder mit mehr Aufwand auch komplexere Verschachtelungen erstellen. Das folgende kleine Shellskript automatisiert die Simulation von MetaLib, bzw. Benutzereingabe vollständig. Lediglich die Dateien test_find und test_present müssen für veränderte Suchanfragen angepasst werden.

  #!/bin/sh
  cat test_find | ./l_huib_elis_find | grep '^FIND' > test.tmp
  cat test.tmp test_present |  ./l_huib_elis_present
  rm test.tmp

Der Ablauf ist folgender: cat gibt die Anfragen aus test_find an l_huib_elis_find weiter, dessen Ausgabe wiederum von grep nach einer Zeile, die mit FIND beginnt, durchsucht wird und das Ergebnis in die (temporäre) Datei test.tmp geschrieben wird. cat gibt nun nacheinander den Inhalt der Dateien test.tmp und test_present an ./l_huib_elis_present weiter, dessen Ausgabe daraufhin auf dem Bildschirm erscheint. Anschließend wird die temporäre Datei test.tmp gelöscht.

Noch einfacher läßt sich das gewünschte Verhalten mit dem konsequenten Einsatz von cat erreichen:

  cat test_find | ./l_huib_elis_find | cat - test_present

Der Trick ist hierbei, dass cat - zunächst von der Standardeingabe liest, diese und anschließend die angegebenen Dateien ausgibt.

3. Funktionsweise der External Hooks bei MetaLib

MetaLib ist eine hochgradig modulare Software, deren Funktionalität im Rahmen des Einsatzbereichs als Bibliotheks- und Wissenschaftsportal erheblich erweitert werden kann. Als zentrales OPAC-Modul kommt das ExLibris-hauseigene Aleph-System zum Einsatz. Darüber hinaus bietet MetaLib aber die Möglichkeit, über den "Universal Gateway" Z39.50-Server anzusprechen und auszuwerten. Für alle anderen Datenquellen, also WWW-Server, XML-Schnittstellen von Informationsanbietern und ähnliches, sind die External Hooks gedacht. Sie erlauben es, beliebige Anbieter, deren Daten sich in bibliografische Formate konvertieren lassen, in das Portfolio der durchsuchbaren Resourcen aufzunehmen. Dadurch, dass die External Hooks eigenständige Programme sind, können sie einfach migriert, angepasst und erweitert werden.

Schematisch sieht die Architektur von MetaLib folgendermaßen aus:

Abb. 1: Schematischer Aufbau von MetaLib
Abb. 1: Schematischer Aufbau von MetaLib
(Quelle: Lohrum, Stefan: MetaLib-Schulung : WWW Server als Targets, 2002, ZIB Berlin, S.3 [leicht modifiziert])

Besonders aufschlussreich an dieser Grafik ist vor Allem, dass sowohl die Z39.50-Konnektoren (unten links), als auch die External Hooks (unten, mitte) über den "Universal Gateway" in MetaLib integriert werden. Das erklärt das zunächst etwas befremdliche Konzept der Trennung zwischen Suche und Darstellung, denn Z39.50 funktioniert genau nach diesem Prinzip.

Hinzuzufügen sei auch noch, dass die External Hooks nicht nur auf das HTTP-Protokoll beschränkt sind. Perl ist eine sehr mächtige Programmiersprache, insbesondere dank der vielen verfügbaren Module, die die Funktionalität erweitern, und es wäre theorethisch möglich, beliebige Aktionen, ausgehend von der Benutzereingabe, auszuführen, bspw. könnte ein FTP-Server oder P2P-Netzwerke nach passenden Dokumenten durchsucht werden. Man könnte sogar so weit gehen, eine Z39.50-Schnittstelle oder die eigene MetaLib-Instanz anzusprechen, wobei das natürlich keinen Sinn ergeben würde.[7] Die Beispiele sollen nur demonstrieren, dass die External Hooks in der Tat sehr mächtig sind und weit mehr können, als nur HTML-Seiten parsen.

Im Folgenden werden die wichtigsten Informationen zum tatsächlichen Einbinden von External Hooks in MetaLib beschrieben.

3. 1. Protokoll

Der Umfang des Wortschatzes, der bei der Kommunikation zwischen MetaLib und External Hook verwendet wird, ist recht gering. Betrachtet man die MetaLib-Software als Server und die Skripte als Client, so ergibt sich folgender beispielhafter Kommunikationsablauf:


MetaLib an find-Skript:

FIND-REQUEST=WRD=(bibliothek AND wissenschaft)

find-Skript an MetaLib:

SET-RESULT=65
FIND-REQUEST=33e8f3a4d6

MetaLib an present-Skript:

FIND-REQUEST=33e8f3a4d6
SET-ENTRY=0
MAX-RECORD=1

present-Skript an MetaLib:

RECORD-FORMAT="PLAIN"
RECORD
100-1 $$aEwert, G.
100-1 $$aUmstätter, W.
245-1 $$aLehrbuch der Bibliotheksverwaltung
YR $$a1997
END-RECORD
END-OF-DATA

Hier geschieht folgendes:

  1. Der Nutzer gibt die Begriffe bibliothek und wissenschaft in die freie Suche ein und MetaLib übergibt die Informationen an das find-Skript.
  2. Das find-Skript durchsucht die externe Quelle. Die Suche ergibt 65 Treffer und das Ergebnis wird auf dem externen Server unter der Zeichenkette 33e8f3a4d6 im Cache gehalten.
  3. Das present-Skript greift direkt auf das mit der Zeichenkete 33e8f3a4d6 gepufferte Suchergebnis zu und gibt alle Suchergebnisse vom 0. bis zum 1. im Datenformat "PLAIN" aus, wobei "PLAIN" hier im wesentlichen USMARC bedeutet. Der eine angeforderte Datensatz wird eingeschlossen von RECORD und END-RECORD und nach Ausgabe aller Datensätze signalisiert END-OF-DATA den Abschluss der Kommunikation zwischen eetaLib und Skripten.

Sehr nützlich ist auch der Befehl ERROR, mit dem eine Fehlermeldung an MetaLib zurückgegeben werden kann. Falls bspw. ein Verbindungsfehler auftritt kann dies mit dem folgenden Skript an MetaLib und damit auch an den Benutzer weitergegeben werden:

  if ($http_status=501) {
    print "ERROR=Der Dienst ist im Moment nicht verfügbar."
  }

Besondere Sorgfalt sollte man auf das Parsen der Eingabe im find-Skript verwenden, denn sowohl einzelne Suchwörter, als auch die Datenfelder werden mit booleschen Operatoren verknüpft. Dabei ist zu beachten, dass die Suchworte in Klammern stehen. Als Feldbezeichner können folgende Zeichenketten von MetaLib übergeben werden: [8]

WRD alle Felder
WAU Autor
WTI Titel
WSU Schlagwort
ISSN ISSN
ISBN ISBN
WYR Jahr

Abschließend sei darauf hingewiesen, dass die Variable FIND_REQUEST bei jeder Suchanfrage tatsächlich dreimal verwendet wird, aber in zwei unterschiedlichen Bedeutungen. FIND_REQUEST kann

  1. die vom Benutzer eingegebene Suchanfrage
  2. die vom find- an das present-Skript weitergereichte Identifikationszeichenkette eines eventuell gecachten Ergebnisses

bedeuten.
Nur die 1. Variante ist obligatorisch. In vielen Fällen wird eine externe Datenquelle über keine nutzbare Cache-Funktionalität verfügen und in diesem Fall macht es wenig Sinn, FIND-REQUEST an MetaLib zurückzugeben. [9]

Für eine elaborierte Erläuterung des Protokolls sind S.34-39 des Resource Management Guides [10] zu konsultieren.

3. 2. Speicherorte

Nachdem die Skripte auf der Kommadozeile das tun, was sie sollten, kann man daran gehen, sie in die MetaLib-Software einzubinden. Die ersten Schritte dazu sind, die Skripte unter dem richtigen Namen und dem richtigen Pfad abzuspeichern und im Suchpfad von MetaLib zu verlinken.
Als Namenskonvention ist das folgende Schema verbreitet:
l_[Abkürzung der eigenen Instititution]_[Abkürzung der externen Quelle]_[find|present|present_single]

Möchte man als Angehörige des Instituts für Bibliotheks- und Informationswissenschaft an der Humboldt-Universität zu Berlin (huib) einen External Hook zum fachbezogenen Repository E-LIS (elis) erstellen, sollten die Namen der Skripte entsprechend

l_huib_elis_find

bzw.

l_huib_elis_present

lauten. Falls weitere Differenzierung notwendig ist, etwa weil man auf eine Quelle zugreift, für die es bereits ein Skript gibt, das aber eine andere Schnittstelle nutzt, so fügt man die zusätzliche Angabe am besten zwischen dem Namen der Quelle und dem Skripttyp ein. Angenommen, E-LIS böte eine XML-Schnittstelle, so wäre

l_huib_elis_xml_find

ein guter Name für ein entsprechendes find-Skript. Durch konsequente Einhaltung dieser Konvention wird der Austausch von Skripten mit anderen MetaLib-Anwendern und die Einarbeitung in die Knowledge Base vereinfacht.
Die Skripte sollten physisch im Verzeichnis

~/m3_3/vir_ext/

abgelegt werden. Abschließend müssen noch symbolische Links zu den Skripten im Verzeichnis

/exlibris/metalib/m3_3/dat01/vir_ext

angelegt werden. Am besten wechselt man einfach in das Verzeichnis und erzeugt die Links mit ln, z.B. für die vorgenannten Skripte:

  cd /exlibris/metalib/m3_3/dat01/vir_ext
  ln -s ~/m3_3/vir_ext/l_huib_elis_find
  ln -s ~/m3_3/vir_ext/l_huib_elis_present

Zu diesem Zeitpunkt ist der External Hook also funktionsfähig und unter richtigem Namen im richtigen Verzeichnis gespeichert und verlinkt. Nun muss nur noch in die MetaLib-Software integriert werden.

3. 3. Konfiguration der MetaLib-Software

An dieser Stelle ist es wichtig zu unterscheiden zwischen Resource und Konfiguration. Metaphorisch gesprochen ist die Resource der Einband und die Konfiguration das Buch, d.h. in der Resource wird für Benutzer und internen Gebrauch gespeichert, welche Informationen diese Resource bietet (Metainformationen), während die Konfiguration rein technisch die Einbindung von Inhalten ermöglicht (Die Informationen selbst). Durch diese zusätzliche Modularisierung, lassen sich in MetaLib die gleichen Datenbanken oder OPACs in unterschiedlichen, thematischen Kontexten und von unterschiedlichen Institutionen einbinden. Um also einen External Hook in MetaLib einzubinden, muss zunächst eine neue Resource erstellt werden, dann eine neue Konfiguration und schließlich beide miteinander verbunden werden.
Konkret muss man sich in den Administrationsbreich von MetaLib einloggen und eine neue Resource hinzufügen ("Add a New Resource"). Das sich daraufhin öffnende Konfigurationsformular sollte man so aussagekräftig wie möglich ausfüllen, wobei man sich bestehende Konfigurationen als Vorlage nehmen kann. [11] Nachdem das Formular ausgefüllt und abgeschickt ist, existiert zwar die neue Resource, ihr ist aber noch keine Konfiguration zugewiesen. Das geschieht im nächsten Schritt.
In der Resourcenliste sucht man die so eben angelegte und öffnet durch Klick auf das kleine A in der Spalte "Config Action" den Konfigurationsdialog. Dort trägt man im Bereich "Add a new configuration" in Großbuchstaben den Dateinamen der Skripte ohne Skripttypbezeichnung (also z.B. L_HUIB_ELIS) ein und wählt als "Access Method" EXTERNAL.
Daraufhin folgt die eigentliche Einrichtung der Skripte. Im Bereich "General" müssen die Namen der Skripte exakt eingetragen werden, z.B.
Find Module l_huib_elis_find
Present Module l_huib_elis_present

Als "Record Type" sollte man PLAIN eintragen, denn das ist grundsätzlich das zu empfehlende Ausgabeformat für das present-Skript [12]. Im Bereich "Term Transformation" muss im Normalfall nichts eingetragen werden, ob und wann doch sollte im MetaLib-Handbuch [13] nachgeschlagen werden. Auch der Bereich "Conversion" sollte recht minimalistisch ausfallen, ein einfacher Eintrag von vir_fix_doc_standard, dem Standard-Konversionsprogramm im Feld "Conversion program" sollte genügen.
Nach dem Speichern der Einstellungen ("SAVE & EXIT") sollte die Resource nebst Konfigurationscode in der Liste der Resourcen erscheinen. Hier muss man noch einmal sichergehen, ob der Status auf "aktiv" (Radiobutton neben dem "A" in der Spalte "Status") gesetzt ist, bevor im Benutzerinterface getestet werden kann, ob die Suche in der neuen Resource funktioniert.

4. Programmierung am Beispiel E-LIS

Im Folgenden werden das find- und present-Skript für einen Hook zu E-LIS detailliert beschrieben.

4. 1. find - Skript

#!/usr/bin/perl
use LWP::Simple;
use LWP::UserAgent;
$|++;

Vor dem eigentlichen Programmablauf werden zwei Submodule des Standardmoduls LWP geladen, das die einfache Kommunikation über HTTP ermöglicht. Außerdem wird durch Setzen der speziellen Variable $| die Ausgabe ungepuffert ausgegeben.

while ($line = <STDIN>) {
  if ($line =~ /^FIND-REQUEST/) {
    ($find_request) = $line =~ /^FIND-REQUEST=\s*(.*)/
  }
}

Die while-Schleife liest solange von der Standardeingabe, bis das Dateiende-Signal eingegeben wird. Zeilen, die nicht mit FIND-REQUEST beginnen, werden ignoriert. Der eigentliche Suchstring nach FIND-REQUEST= wird der Variablen $find_request zugewiesen.

%map = ('WRD' => '_fulltext_',
        'WTI' => 'title',
        'WAU' => 'authors',
        'WYR' => 'year',
        'WSU' => 'keywords'
       );
foreach (split(/\)\s*[ANDORNT]+?\s+?/, $find_request)) {
  ($ccl) = $_ =~ /(W[A-Z]+)\s*=\s*\(.+?\)/;
  ($query{$ccl}) = $_ =~ /W[A-Z]+\s*=\s*\((.+?)\)/;
  if ($query{$ccl} =~ / OR /) {
    $boolean{$ccl} = "$map{$ccl}_merge=ANY";
  } else {
    $boolean{$ccl} = "$map{$ccl}_merge=ALL";
  } 
  $query{$ccl} =~ s/ AND /\+/;
  $query{$ccl} =~ s/ OR /\+/;
  $query{$ccl} =~ s/ NOT (.+?)[\s]//;
}

In diesem Abschnitt erfolgt mithilfe der assoziativen Arrays %map, %query und %boolean die Umsetzung der von MetaLib übergebenen Daten in solche, die in der URL an E-LIS geschickt werden. Im Einzelnen:

Die foreach-Schleife durchläuft alle Feldname-Feldwert-Tupel und zerlegt diese wiederum in den Feldnamen ($ccl), die Anfrage ($query{$ccl}) und den zugehörigen booleschen Operationsmodus. Anschließend werden die booleschen Operatoren in Pluszeichen umgewandelt (AND,OR), bzw. übergangen (NOT). [15]

$url = "http://eprints.rclis.org/perl/search/advanced?linguabib=en&linguabib=de&linguabib_merge=ANY&";
while (($command, $query) = each(%query)) {
  $url .= "$map{$command}=$query&";
  $url .= "$boolean{$command}&";
}
$url .= "_action_search=Search";

Dieser Programmteil erzeugt die URL, aus den assoziativen Arrays. Deren Elemente werden mit dem Grundgerüst, das "fest-verdrahtete" Angaben über die bevorzugte Sprache der Suchergebnisse (deutsch oder englisch) enthält, konkateniert.

$ua = new LWP::UserAgent;
$ua->agent("HUIB/METALIB");
my $http_query = new HTTP::Request('GET', $url);
my $response = $ua->request($http_query);
$raw_html = $response->content;
 
($cachenummer) = $raw_html =~ /\/perl\/search\/advanced\?_cache=(\d+)&amp;_/;
($ergebnisse) = $raw_html =~ /Displaying results.+>(.+)<\/span>\./;

Im nächsten Schritt wird die Anfrage abgeschickt. [16] Der Inhalt des HTML-Antwort wird nach der $cachenummer durchsucht, die es dem present-Skript ermöglichen wird, direkt auf das Suchergebnis zuzugreifen, sodass E-LIS nicht noch einmal die eigene Datenbank durchsuchen muss. Anschließend wird noch die Anzahl der Ergebnisse ausgelesen und der Variablen $ergebnisse zuegewiesen.

print "SET-RESULT=$ergebnisse\n";
print "FIND-REQUEST=$cachenummer\n";

Ganz zum Schluss werden Ergebnisanzahl und Cachenummer dem Protokoll gemäß an die Standardausgabe und damit an MetaLib geschrieben. Aus Sicht des Benutzers hält MetaLib nun einen Moment inne, lädt die Seite neu und zeigt die Anzahl der Suchergebnisse an. Gleichzeitig wird das present-Skript aufgerufen, um die konkreten Suchergebnisse abzurufen.

4. 2. present - Skript

#!/usr/bin/perl
use LWP::Simple;
use LWP::UserAgent;
$|++;
while ( $line=<STDIN> )  {
  if ( $line=~ /^FIND-REQUEST/ ) {
    ($find_request) = $line =~ /FIND-REQUEST=(.*)/;
  }
  if ( $line=~ /^SET-ENTRY/ ) {
    ($set_entry) = $line =~ /SET-ENTRY=(.*)/;
  }
  if ( $line=~ /^MAX-RECORD/ ) {
    ($max_record) = $line =~ /MAX-RECORD=(.*)/;
  }
}
$ua = new LWP::UserAgent;
$ua->agent('HUIB/METALIB');
$url = "http://eprints.rclis.org/perl/search/advanced?_cache=$find_request&_offset=$set_entry";
$request = new HTTP::Request('GET', $url); 
$response = $ua->request($request);
$rawhtml = $response->content;

Bis hierher geschieht nichts, was nicht schon im find-Skript vorgekommen ist: Module werden initialisiert, die Standardeingabe gelesen, diesmal drei Zeilen, und mit der übergebenen Cache-Nummer ($find_request) und der Nummer des ersten zu holenden Ergebnisses ($set_entry) wird eine URL erzeugt. Die Anfrage wird abgeschickt und die HTML-Antwort der Variablen $rawhtml zugewiesen.

$rawhtml =~ s/[\r\t\n]//g;
@felder = split(/<\/p><p>/, $rawhtml);

Nun werden irrelevante und problembehaftete Zeichen (Wagenrücklauf, Tabulator, Zeilenumbruch) entfernt und der HTML-Quelltext in einzelne Datensätze aufgeteilt und diese dem Array @felder zugewiesen. Hier kommt es sehr gelegen, dass die Macher von E-LIS sauber gekapseltes HTML anbieten. Alle Datensätze sind in eigenen Absätzen zu finden und die Datenfelder sind mit Klassenbezeichnungen in <span>-Tags semantisch ausgezeichnet - ein mustergültiges Repository.

foreach (@felder) {
  if ($i++ >= ($max_record - $set_entry)) {
    last;
  }
  $feld = $_;
  ($titel) = $feld =~ /<span class="field_title">(.+?)<\/span>/;
  ($jahr) = $feld =~ /<span class="field_year">(.+?)<\/span>/;
  ($url) = $feld =~ /<a href="(.+?)">/;
  ($konferenz) = $feld =~ /<span class="field_conference">(.+?)<\/span>/;
  ($ort) = $feld =~ /<span class="field_confloc">(.+?)<\/span>/;
  ($autor) = $feld =~ /<span class="field_authors">(.+?)<\/span> \(/;
  $autoren = join('; ', ($autor =~ /<span class="person_name">(.+?)<\/span>/g));

Die einzelnen Datensätze werden nun wieder in einer foreach-Schleife durchlaufen. Darin wird zunächst überprüft, ob bereits die durch $max_record festgelegte Höchstanzahl an zurückzugebenden Datensätzen erreicht wurde und bricht in diesem Fall die Schleife ab. Ansonsten werden die bibliographischen Daten aus dem HTML-Quelltext mittels einfacher regulärer Ausdrücke ausgelesen und mnemotechnisch benannten Variablen zugewiesen.

  print "RECORD\n";
  print "100 \$a$autoren\n";
  if ($konferenz) {
    print "110 $konferenz\n";
  }
  print "245 10\$a$titel\n";
  print "856 \$u$url\n";
  print "362 0#\$a$jahr\n";
  print "END-RECORD\n";
}
print "END-OF-DATA\n";

Schließlich erfolgt wieder die Ausgabe der Daten an STDOUT und somit an MetaLib. Das Schema wird von MetaLib intern als PLAIN bezeichnet, entspricht aber USMARC (siehe 3.1. Protokoll und 3.3. Konfiguration der MetaLib-Software). Damit ist der Ablauf vollständig: MetaLib hat die Ergebnisse zur gestellten Suchanfrage in verwertbarem Format erhalten und gibt sie nun als Tabelle an den Benutzer aus.

5. Kritik, Lob

5.1. Kritk

Erweiterbarkeit und Schnittstellen für Skriptsprachen sind heutzutage essentiell für den Erfolg von webbasierter Software. Bei MetaLib ist das nicht anders. Allerdings ist weder die Oberfläche, noch das Interface für die External Hooks einfach, übersichtlich oder gar intuitiv gestaltet. Ohne die vollständige Dokumentation und am besten auch noch professionellen Support vom Hersteller ist es schwierig, sich mit der Software zurechtzufinden. Das ist zum Teil der Tatsache geschuldet, dass MetaLib wie eine "gewachsene Software" wirkt, dass also das Programm schneller gewachsen zu sein scheint, als das dahinterstehende Design, zum Teil muss man aber mutmaßen, dass ExLibris sich entweder nicht in die Karten sehen lassen will oder keinen Wert auf die Verwendung offener Standards legt.
So ist etwa die Substitutionssprache, die für die "Term Transformation" benutzt wird, eine höchst kryptische Eigenentwicklung, deren Funktionalität durch Reguläre Ausdrücke ersetzbar wäre. Ähnliches gilt für das Protokoll, das bei der Kommunikation zwischen find-/present-Skript und MetaLib verwendet wird: Statt XML oder JSON ein eigenentwickeltes, zeilenorientiertes Format, das auch in seinen Elementnamen inkonsistent ist. [17]
Auch die Wahl der Feldnamen für die anfängliche Suchanfrage ist willkürlich. Sie stellt zwar offensichtlich eine Teilmenge der Aleph-CCL dar, explizit erklärt wird das so aber nicht. Der einzige Hinweis auf den semantischen Gehalt der Drei-Buchstaben-Kombinationen findet sich im Resource Management Guide in einem einzige Absatz. [18] Auch auf der Ebene des Betriebssystems kann MetaLib durch die uneingängige Benennung der relevanten Dateien und Ordner sehr verwirrend sein. Vergisst man, sich die Ordnernamen zu notieren, in denen beispielsweise die Logdateien oder die Links zu den Skripten zu finden sind, kann man anschließend stundenlang durch Dutzende, durchnummerierte Ordner navigieren, ohne etwas zu finden.
Schließlich noch ein Kritikpunkt am Prinzip der External Hooks allgemein. Die Trennung von Suche und Darstellung, bzw. find- und present-Skript, macht bei Z39.50- oder Fachinformationssystemen durchaus Sinn, weil diese Systeme selbst für die Nutzung im Sinne von "fire & forget"[19] konzipiert sind. Wenn aber HTML-Ausgaben von WWW-Servern geparset werden, die eigentlich für die unmittelbare Nutzung durch den Menschen gedacht sind und deren Backends entsprechend im Allgemeinen über keine Caching-Funktion für die Suchergebnisse verfügen, verdoppeln sich sowohl Traffic, als auch Rechenaufwand, weil sowohl find-, als auch present-Skript das gleiche Dokument - die komplette Ergebnisliste - anfordern. Ohne die Trennung zwischen Suche und Darstellung ließe sich der External Hook zu E-LIS (siehe 4. Programmierung am Beispiel E-LIS) mit einer einzigen Anfrage und halb so viel Perlcode programmieren.

5.2. Kritik der Kritik

Dass MetaLib so groß und unübersichtlich ist, bedeutet auch, dass es über extrem viele Features verfügt. Hervorstechende Eigenschaften wie SFX und das fein justierbare Rechtemanagement konnten im Rahmen des Projekts gar nicht voll genutzt werden. Was für den unerfahrenen Anwender ein Bug ist, ist für den Experten ein unverzichtbares Feature.
Hinzu kommt, dass MetaLib Konfigurationsmöglichkeiten für beinahe jeden Aspekt der Software bietet, die, wenn man sie kennt und beherrscht, viele Mängel an den Standardeinstellungen (z.B. die willkürlichen Feldnamen oder die "Term Transformation"-Sprache) beseitigen können. MetaLib ist definitv keine einfache Software, aber für den, der sich die Zeit nimmt, die Dokumentation zu lesen, bzw. das Geld hat, um den Support in Anspruch zu nehmen, ein vollständiges, riesiges und mächtiges Werkzeug, um Bibliotheksportale zu unterhalten, die Informationen aus allen Bereichen (OPACs, Z39.50-Server, WWW-Server...) unter einer einheitlichen Oberfläche bieten.
Außerdem ist im Januar die Version 4.0 von MetaLib erschienen, über die in vom Autor mangels Erfahrung keine Aussage getroffen werden kann, die aber sicher viele Verbesserungen und neue Features mit sich gebracht hat.
Es kann nicht abgestritten werden, dass es eine sehr reizvolle Aufgabe war, sich intensiv mit dieser großen und professionellen Software auseinanderzusetzen, auch wenn sie zeitraubend war und gelegentlich sehr strapaziös war.

6. Literatur und Quelltexte

WWW - Seiten

Lokale Quellen

im Ordner Lokale Quellen:

Skripte

im Ordner Skripte
1] Application Programming Interface, d.h. die Schnittstelle zur Programmierung einer Software
2] Artikel Ninety-Ninety Rule, in: Wikipedia, the free encyclopedia, URL: http://en.wikipedia.org/wiki/Ninety-ninety_rule
3] Mikroformate sind semantisch angereicherte XHTML-Dokumente (siehe dazu im Microformats Wiki
4] in Ex Libris: MetaLib Version 3.13, Service Pack 69 Resource Management Guide, 2005, S.34-40
5] zur Benennung der Skripte siehe 3.2. Speicherorte
6] zum Protokoll siehe 3.1. Protokoll
7] MetaLib integriert ja einen generischen Z39.50-Gateway und der Versuch, "sich selbst" zu durchsuchen würde zu einer Endlosschleife und schließlich zu einem Stack Overflow führen, bzw. gar nicht funktionieren.
8] In der Tat kann man auch andere Bezeichnernamen konfigurieren, aber diese sieben Befehle sind der Standard.
9] es sei denn, es müssen andere Daten vom find- an das present-Skript weitergereicht werden. In diesem Fall ist es sogar die einzige Möglichkeit, ohne auf das Dateisystem schreiben zu müssen, was in keinem Fall zu empfehlen ist
10] Ex Libris: Resource Management Guide, 2005, S.34-39
11] dafür sucht man nach einem External Hook in den bestehenden Resourcen, d.h. im Hauptmenü geht man in den Bereich "RESOURCE LIST" und sucht dort in den Resourcen anderer Institutionen ("Filter by Institution") nach einem "Resource Type", der die Verwendung externer Hooks nahelegt, z.B. WWW-Server oder Fachportal. Steht im Suchergebnis in der Spalte "Access Method" "EXTERNAL", so kann die Resource sowohl, was die Beschreibung, als auch die tatsächliche Konfiguration angeht, als Beispiel dienen
12] "Docs mention XML but not how to actually use it", Maijala, Ere: MetaLib External Search Programs, 2005
13] ExLibris: Resource Management Guide, S.47ff
14] Im Grunde ist das nicht das gewünschte Verhalten, denn auf diese Weise werden die Suchanfragen bibliothek AND wissenschaft OR metalib und bibliothek OR wissenschaft AND metalib gleichermaßen falsch wie bibliothek OR wissenschaft OR metalib behandelt, obwohl boolesche Operatoren eigentlich zweistellig sind. Da aber E-LIS nur die Auswertung der gesamten Suchbegriffe eines Termes anbieten, nämlich entweder "es müssen alle gleichzeitig vorhanden sein" (=_merge=ALL) oder "es muss mindestens ein Begriff enthalten sein" (=_merge=ANY, ließe sich das nur sehr aufwändig über mehrere Suchanfragen und anschließende Auswertung lösen, was gleichermaßen traffic- und rechenintensiv wäre.
15] wird von E-LIS nicht unterstützt und wäre sehr aufwändig zu implementieren (siehe Anmerkung [14])
16] Es ist grundsätzlich darauf zu achten, einen Useragent zu setzen ($ua→agent("HUIB/METALIB")), da viele WWW-Dienste Clients mit Standard-Useragents als Angreifer betrachten und ihnen den Zugriff verweigern
17] Beispiele:
  • FIND-REQUEST steht mal für die Suchanfrage des Nutzers, mal für die URL des gecacheten Ergebnisses (siehe auch 3.1. Protokoll)
  • Der erste Datensatz wird mit SET-ENTRY, der letzte mit MAX-RECORD bezeichnet. Konsequent (und intuitiver) wäre es, statt SET-ENTRY MIN-RECORD zu verwenden.
18] in Ex Libris: Resource Management Guide, 2005, S.34 oben
19] gemeint ist die Trennung von Suche und Präsentation