Saganet Z39.50

The goal is to be able to search in the library catalog Gelmir. In this document a brief view into the design and structure of the system will be explained.

Z39.50 Search

This diagram shows a search is done. The web client sends a POST/GET request to the Web Server. The Web Server executes an ASP page that then does a search in the SLS Z39.50 Server which in turn goes to Gelmir for its records. Once it has the records it returns them to ActiveX object which translates the records into ActiveX objects which the ASP layer can then work with.

Our first design was a monolithic design at the Web Server layer. This made it really hard to make changes to the web pages as the CGI scripts all had to be recompiled once a change was made. This prompted us to evaluate different options and redesign the layers and how they interact.

Once this was done we had the current design which essentially decouples the Z39.50 code from the Web pages. The technology used was COM because the development is being done for NT servers. This made it easier to make changes to the search and the user interface. The search parser sits at the ASP page layer so additional search arguments can easily be added.

The Source

The Z39.50 DLL being used is from Index Data in Danmark. The source is available at ftp://ftp.indexdata.dk/index/yaz/ yaz-1.4pl2.tar.gz and documentation can be found at the web site http://www.indexdata.dk/yaz/.

The ActiveX layer can be downloaded here and the version changes are also available. For security reasons the ASP Pages are not available for download but if you are interested in using the ASP layer please contact me and I will send you some useful hints and demo code.

The Interfaces

IZ3950Asp

HRESULT OnStartPage([in] IUnknown* piUnk);
HRESULT OnEndPage();
HRESULT Database([out, retval] BSTR *pVal);
HRESULT Database([in] BSTR newVal);
HRESULT Catalog([out, retval] BSTR *pVal);
HRESULT Catalog([in] BSTR newVal);
HRESULT Password([out, retval] BSTR *pVal);
HRESULT Password([in] BSTR newVal);
HRESULT Host([out, retval] BSTR *pVal);
HRESULT Host([in] BSTR newVal);
HRESULT Port([out, retval] long *pVal);
HRESULT Port([in] long newVal);
HRESULT Connect([out, retval] long *retVal);
HRESULT Find([in] BSTR FindString, [out, retval] long *retVal);
HRESULT GetNextRecord([out, retval] VARIANT* retval);
HRESULT ResultNumber([out, retval] long *pVal);
HRESULT ResultNumber([in] long newVal);
HRESULT GetRecordCollection([out, retval] VARIANT *retval);

IMarcRecordCollection

HRESULT Count([out, retval] long* retval);
HRESULT Item([in] long Index, [out, retval] VARIANT* retval);
HRESULT _NewEnum([out, retval] IUnknown **retval); };

IMarcRecord

HRESULT GetMarcTag([in] long tag, [out, retval] VARIANT * retval);
HRESULT GetTagCollection([out, retval] VARIANT* retval);
HRESULT FindByTag([in] long tag, [out, retval] VARIANT *retval);

IMarcTagCollection

HRESULT Count([out, retval] long* retval);
HRESULT Item([in] long Index, [out, retval] VARIANT* retval);
HRESULT _NewEnum([out, retval] IUnknown **retval);

IMarcTag

HRESULT GetTagNumber([out, retval] BSTR *retval);
HRESULT GetSubTag([in] BSTR SubTag, [out, retval] BSTR *retval);
HRESULT GetSubTagNumber([out, retval] BSTR *retval);
HRESULT GetTagField([out, retval] BSTR *retval);