2 <!-- $Id: zoom.xml,v 1.7 2002-10-11 12:19:09 mike Exp $ -->
3 <title>ZOOM-C++</title>
6 <sect1 id="zoom-introduction">
7 <title>Introduction</title>
9 <ulink url="http://zoom.z3950.org/">ZOOM</ulink>
10 is the emerging standard API for information retrieval programming
11 using the Z39.50 protocol. ZOOM's
12 <ulink url="http://zoom.z3950.org/api/">Abstract API</ulink>
13 specifies semantics for classes representing key IR concepts such as
14 connections, queries, result sets and records; and there are various
15 <ulink url="http://zoom.z3950.org/bind/">bindings</ulink>
16 specifying how those concepts should be represented in various
17 programming languages.
20 The Yaz++ library includes an implementation of the <ulink
21 url="http://zoom.z3950.org/bind/cplusplus/"
23 for ZOOM, enabling quick, easy development of client applications.
26 For example, here is a tiny Z39.50 client that fetches and displays
27 the MARC record for Farlow & Brett Surman's
28 <citetitle>The Complete Dinosaur</citetitle>
29 from the Library of Congress's Z39.50 server:
32 #include <iostream>
33 #include <yaz++/zoom.h>
37 int main(int argc, char **argv)
39 connection conn("z3950.loc.gov", 7090);
40 conn.option("databaseName", "Voyager");
41 conn.option("preferredRecordSyntax", "USMARC");
42 resultSet rs(conn, prefixQuery("@attr 1=7 0253333490"));
43 const record *rec = rs.getRecord(0);
44 cout << rec->render() << endl;
48 (Note that, for the sake of simplicity, this program does not check
49 for errors: we show a more robust version of the same program
50 <link linkend="revised-sample">later</link>.)
53 Yaz++'s implementation of the C++ binding is a thin layer over Yaz's
54 implementation of the C binding. For information on the supported
55 options and other such details, see the ZOOM-C documentation, which
56 can be found on-line at
57 <ulink url="http://www.indexdata.dk/yaz/doc/zoom.php"/>
60 All of the classes defined by ZOOM-C++ are in the
61 <literal>ZOOM</literal> namespace. We will now consider
62 the five main classes in turn:
67 <literal>connection</literal>
73 <literal>query</literal> and its subclasses
74 <literal>prefixQuery</literal> and
75 <literal>CCLQuery</literal>
81 <literal>resultSet</literal>
87 <literal>record</literal>
93 <literal>exception</literal> and its subclasses
94 <literal>systemException</literal>,
95 <literal>bib1Exception</literal> and
96 <literal>queryException</literal>
104 <sect1 id="zoom-connection">
105 <title><literal>ZOOM::connection</literal></title>
107 A <literal>ZOOM::connection</literal> object represents an open
108 connection to a Z39.50 server. Such a connection is forged by
109 constructing a <literal>connection</literal> object.
112 The class has this declaration:
117 connection (const char *hostname, int portnum);
119 const char *option (const char *key) const;
120 const char *option (const char *key, const char *val);
124 When a new <literal>connection</literal> is created, the hostname
125 and port number of a Z39.50 server must be supplied, and the
126 network connection is forged and wrapped in the new object. If the
127 connection can't be established - perhaps because the hostname
128 couldn't be resolved, or there is no server listening on the
129 specified port - then an
130 <link linkend="zoom-exception"><literal>exception</literal></link>
134 The only other methods on a <literal>connection</literal> object
135 are for getting and setting options. Any name-value pair of
136 strings may be set as options, and subsequently retrieved, but
137 certain options have special meanings which are understood by the
138 ZOOM code and affect the behaviour of the object that carries
139 them. For example, the value of the
140 <literal>databaseName</literal> option is used as the name of the
141 database to query when a search is executed against the
142 <literal>connection</literal>. For a full list of such special
143 options, see the ZOOM abstract API and the ZOOM-C documentation
148 <title>References</title>
152 <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.2"
153 >Section 3.2 (Connection) of the ZOOM Abstract API</ulink>
158 <ulink url="http://www.indexdata.dk/yaz/doc/zoom.php#zoom.connections"
159 >The Connections section of the ZOOM-C documentation</ulink>
167 <sect1 id="zoom-query">
168 <title><literal>ZOOM::query</literal> and subclasses</title>
170 The <literal>ZOOM::query</literal> class is a virtual base class,
171 representing a query to be submitted to a server. This class has
172 no methods, but two (so far) concrete subclasses, each implementing
173 a specific query notation.
177 <title><literal>ZOOM::prefixQuery</literal></title>
179 class prefixQuery : public query {
181 prefixQuery (const char *pqn);
186 This class enables a query to be created by compiling Yaz's
188 <ulink url="http://www.indexdata.dk/yaz/doc/tools.php#PQF"
189 >Prefix Query Notation (PQN)</ulink>.
194 <title><literal>ZOOM::CCLQuery</literal></title>
196 class CCLQuery : public query {
198 CCLQuery (const char *ccl, void *qualset);
203 This class enables a query to be created using the simpler but
205 <ulink url="http://www.indexdata.dk/yaz/doc/tools.php#CCL"
206 >Common Command Language (CCL)</ulink>.
207 The qualifiers recognised by the CCL parser are specified in an
208 external configuration file in the format described by the Yaz
212 If query construction fails for either type of
213 <literal>query</literal> object - typically because the query
214 string itself is not valid PQN or CCL - then an
215 <link linkend="zoom-exception"><literal>exception</literal></link>
221 <title>Discussion</title>
223 It will be readily recognised that these objects have no methods
224 other than their constructors: their only role in life is to be
225 used in searching, by being passed to the
226 <literal>resultSet</literal> class's constructor.
229 Given a suitable set of CCL qualifiers, the following pairs of
230 queries are equivalent:
233 prefixQuery("dinosaur");
234 CCLQuery("dinosaur");
236 prefixQuery("@and complete dinosaur");
237 CCLQuery("complete and dinosaur");
239 prefixQuery("@and complete @or dinosaur pterosaur");
240 CCLQuery("complete and (dinosaur or pterosaur)");
242 prefixQuery("@attr 1=7 0253333490");
243 CCLQuery("isbn=0253333490");
248 <title>References</title>
252 <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.3"
253 >Section 3.3 (Query) of the ZOOM Abstract API</ulink>
258 <ulink url="http://www.indexdata.dk/yaz/doc/zoom.query.php"
259 >The Queries section of the ZOOM-C documentation</ulink>
267 <sect1 id="zoom-resultset">
268 <title><literal>ZOOM::resultSet</literal></title>
270 A <literal>ZOOM::resultSet</literal> object represents a set of
271 records identified by a query that has been executed against a
272 particular connection. The sole purpose of both
273 <literal>connection</literal> and <literal>query</literal> objects
274 is that they can be used to create new
275 <literal>resultSet</literal>s - that is, to perform a search on the
276 server on the remote end of the connection.
279 The class has this declaration:
284 resultSet (connection &c, const query &q);
286 const char *option (const char *key) const;
287 const char *option (const char *key, const char *val);
288 size_t size () const;
289 const record *getRecord (size_t i) const;
293 New <literal>resultSet</literal>s are created by the constructor,
294 which is passed a <literal>connection</literal>, indicating the
295 server on which the search is to be performed, and a
296 <literal>query</literal>, indicating what search to perform. If
297 the search fails - for example, because the query uses attributes
298 that the server doesn't implement - then an
299 <link linkend="zoom-exception"><literal>exception</literal></link>
303 Like <literal>connection</literal>s, <literal>resultSet</literal>
304 objects can carry name-value options. The special options which
305 affect ZOOM-C++'s behaviour are the same as those for ZOOM-C and
306 are described in its documentation (link below). In particular,
307 the <literal>preferredRecordSyntax</literal> option may be set to
308 a string such as ``USMARC'', ``SUTRS'' etc. to indicate what the
309 format in which records should be retrieved; and the
310 <literal>elementSetName</literal> option indicates whether brief
311 records (``B''), full records (``F'') or some other composition
315 The <literal>size()</literal> method returns the number of records
316 in the result set. Zero is a legitimate value: a search that finds
317 no records is not the same as a search that fails.
320 Finally, the <literal>getRecord</literal> method returns the
321 <parameter>i</parameter>th record from the result set, where
322 <parameter>i</parameter> is zero-based: that is, legitmate values
323 range from zero up to one less than the result-set size. If the
324 method fails, for example because the requested record is out of
325 range, it <literal>throw</literal>s an
326 <link linkend="zoom-exception"><literal>exception</literal></link>.
330 <title>References</title>
334 <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.4"
335 >Section 3.4 (Result Set) of the ZOOM Abstract API</ulink>
340 <ulink url="http://www.indexdata.dk/yaz/doc/zoom.resultsets.php"
341 >The Result Sets section of the ZOOM-C documentation</ulink>
349 <sect1 id="zoom-record">
350 <title><literal>ZOOM::record</literal></title>
352 A <literal>ZOOM::record</literal> object represents a chunk of data
353 from a <literal>resultSet</literal> returned from a server.
356 The class has this declaration:
363 UNKNOWN, GRS1, SUTRS, USMARC, UKMARC, XML
365 record *clone () const;
366 syntax recsyn () const;
367 const char *render () const;
368 const char *rawdata () const;
372 Records returned from Z39.50 servers are encoded using a record
373 syntax: the various national MARC formats are commonly used for
374 bibliographic data, GRS-1 or XML for complex structured data, SUTRS
375 for simple human-readable text, etc. The
376 <literal>record::syntax</literal> enumeration specifies constants
377 representing common record syntaxes, and the
378 <literal>recsyn()</literal> method returns the value corresponding
379 to the record-syntax of the record on which it is invoked.
382 Because this interface uses an enumeration, it is difficult to
383 extend to other record syntaxes - for example, DANMARC, the MARC
384 variant widely used in Denmark. We might either grow the
385 enumeration substantially, or change the interface to return
386 either an integer or a string.
391 The simplest thing to do with a retrieved record is simply to
392 <literal>render()</literal> it. This returns a human-readable, but
393 not necessarily very pretty, representation of the contents of the
394 record. This is useful primarily for testing and debugging, since
395 the application has no control over how the record appears.
396 (The application must <emphasis>not</emphasis>
397 <literal>delete</literal> the returned string - it is ``owned'' by
401 More sophisticated applications will want to deal with the raw data
402 themselves: the <literal>rawdata()</literal> method returns it.
403 Its format will vary depending on the record syntax: SUTRS, MARC
404 and XML records are returned ``as is'', and GRS-1 records as a
405 pointer to their top-level node, which is a
406 <literal>Z_GenericRecord</literal> structure as defined in the
407 <literal><yaz/z-grs.h></literal> header file.
408 (The application must <emphasis>not</emphasis>
409 <literal>delete</literal> the returned data - it is ``owned'' by
413 Perceptive readers will notice that there are no methods for access
414 to individual fields within a record. That's because the different
415 record syntaxes are so different that there is no even a uniform
416 notion of what a field is across them all, let alone a sensible way
417 to implement such a function. Fetch the raw data instead, and pick
418 it apart ``by hand''.
422 <title>Memory Management</title>
424 The <literal>record</literal> obejcts returned from
425 <literal>resultSet::getRecord()</literal> are ``owned'' by the
426 result set object: that means that the application is not
427 responsible for <literal>delete</literal>ing them - each
428 <literal>record</literal> is automatically deallocated when the
429 <literal>resultSet</literal> that owns it is
430 <literal>delete</literal>d.
433 Usually that's what you want: it means that you can easily fetch a
434 record, use it and forget all about it, like this:
437 resultSet rs(conn, query);
438 cout << rs.getRecord(0)->render();
441 But sometimes you want a <literal>record</literal> to live on past
442 the lifetime of the <literal>resultSet</literal> from which it was
443 fetched. In this case, the <literal>clone(f)</literal> method can
444 be used to make an autonomous copy. The application must
445 <literal>delete</literal> it when it doesn't need it any longer:
450 resultSet rs(conn, query);
451 rec = rs.getRecord(0)->clone();
452 // `rs' goes out of scope here, and is deleted
454 cout << rec->render();
460 <title>References</title>
464 <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.5"
465 >Section 3.5 (Record) of the ZOOM Abstract API</ulink>
470 <ulink url="http://www.indexdata.dk/yaz/doc/zoom.records.php"
471 >The Records section of the ZOOM-C documentation</ulink>
479 <sect1 id="zoom-exception">
480 <title><literal>ZOOM::exception</literal> and subclasses</title>
482 The <literal>ZOOM::exception</literal> class is a virtual base
483 class, representing a diagnostic generated by the ZOOM-C++ library
484 or returned from a server. Its subclasses represent particular
488 When any of the ZOOM methods fail, they respond by
489 <literal>throw</literal>ing an object of type
490 <literal>exception</literal> or one of its subclasses. This most
491 usually happens with the <literal>connection</literal> constructor,
492 the various query constructors, the <literal>resultSet</literal>
493 constructor (which is actually the searching method) and
494 <literal>resultSet::getRecord()</literal>.
497 The base class has this declaration:
502 exception (int code);
503 int errcode () const;
504 const char *errmsg () const;
508 It has three concrete subclasses:
512 <title><literal>ZOOM::systemException</literal></title>
514 class systemException: public exception {
517 int errcode () const;
518 const char *errmsg () const;
522 Represents a ``system error'', typically indicating that a system
523 call failed - often in the low-level networking code that
524 underlies Z39.50. <literal>errcode()</literal> returns the value
525 that the system variable <literal>errno</literal> had at the time
526 the exception was constructed; and <literal>errmsg()</literal>
527 returns a human-readable error-message corresponidng to that error
533 <title><literal>ZOOM::bib1Exception</literal></title>
535 class bib1Exception: public exception {
537 bib1Exception (int errcode, const char *addinfo);
538 int errcode () const;
539 const char *errmsg () const;
540 const char *addinfo () const;
544 Represents an error condition communicated by a Z39.50 server.
545 <literal>errcode()</literal> returns the BIB-1 diagnostic code of
546 the error, and <literal>errmsg()</literal> a human-readable error
547 message corresponding to that code. <literal>addinfo()</literal>
548 returns any additional information associated with the error.
551 For example, if a ZOOM application tries to search in the
552 ``Voyager'' database of a server that does not have a database of
553 that name, a <literal>bib1Exception</literal> will be thrown in
554 which <literal>errcode()</literal> returns 109,
555 <literal>errmsg()</literal> returns the corresponding error
556 message ``Database unavailable'' and <literal>addinfo()</literal>
557 returns the name of the requested, but unavailable, database.
562 <title><literal>ZOOM::queryException</literal></title>
564 class queryException: public exception {
566 static const int PREFIX = 1;
567 static const int CCL = 2;
568 queryException (int qtype, const char *source);
569 int errcode () const;
570 const char *errmsg () const;
571 const char *addinfo () const;
575 This class represents an error in parsing a query into a form that
576 a Z39.50 can understand. It must be created with the
577 <literal>qtype</literal> parameter equal to one of the query-type
578 constants, which can be retrieved via the
579 <literal>errcode()</literal> method; <literal>errmsg()</literal>
580 returns an error-message specifying which kind of query was
581 malformed; and <literal>addinfo()</literal> returns a copy of the
582 query itself (that is, the value of <literal>source</literal> with
583 which the exception object was created.)
587 <sect2 id="revised-sample">
588 <title>Revised Sample Program</title>
590 Now we can revise the sample program from the
591 <link linkend="zoom-introduction">introduction</link>
592 to catch exceptions and report any errors:
595 /* g++ -o zoom-c++-hw zoom-c++-hw.cpp -lyaz++ -lyaz */
597 #include <iostream>
598 #include <yaz++/zoom.h>
600 using namespace ZOOM;
602 int main(int argc, char **argv)
605 connection conn("z3950.loc.gov", 7090);
606 conn.option("databaseName", "Voyager");
607 conn.option("preferredRecordSyntax", "USMARC");
608 resultSet rs(conn, prefixQuery("@attr 1=7 0253333490"));
609 const record *rec = rs.getRecord(0);
610 cout << rec->render() << endl;
611 } catch (systemException &e) {
612 cerr << "System error " <<
613 e.errcode() << " (" << e.errmsg() << ")" << endl;
614 } catch (bib1Exception &e) {
615 cerr << "BIB-1 error " <<
616 e.errcode() << " (" << e.errmsg() << "): " << e.addinfo() << endl;
617 } catch (queryException &e) {
618 cerr << "Query error " <<
619 e.errcode() << " (" << e.errmsg() << "): " << e.addinfo() << endl;
620 } catch (exception &e) {
621 cerr << "Error " <<
622 e.errcode() << " (" << e.errmsg() << ")" << endl;
627 The heart of this program is the same as in the original version,
628 but it's now wrapped in a <literal>try</literal> block followed by
629 several <literal>catch</literal> blocks which try to give helpful
630 diagnostics if something goes wrong.
633 The first such block diagnoses system-level errors such as memory
634 exhaustion or a network connection being broken by a server's
635 untimely death; the second catches errors at the Z39.50 level,
636 such as a server's report that it can't provide records in USMARC
637 syntax; the third is there in case there's something wrong with
638 the syntax of the query (although in this case it's correct); and
639 finally, the last <literal>catch</literal> block is a
640 belt-and-braces measure to be sure that nothing escapes us.
645 <title>References</title>
649 <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.7"
650 >Section 3.7 (Exception) of the ZOOM Abstract API</ulink>
655 <ulink url="http://lcweb.loc.gov/z3950/agency/defns/bib1diag.html"
656 >Bib-1 Diagnostics</ulink> on the
657 <ulink url="http://lcweb.loc.gov/z3950/agency/"
658 >Z39.50 Maintenance Agency</ulink> site.
663 Because C does not support exceptions, ZOOM-C has no API element
664 that corresponds directly with ZOOM-C++'s
665 <literal>exception</literal> class and its subclasses. The
666 closest thing is the <literal>ZOOM_connection_error</literal>
667 function described in
668 <ulink url="http://www.indexdata.dk/yaz/doc/zoom.php#zoom.connections"
669 >The Connections section</ulink> of the documentation.
676 <!-- Keep this comment at the end of the file
681 sgml-minimize-attributes:nil
682 sgml-always-quote-attributes:t
685 sgml-parent-document: "zebra.xml"
686 sgml-local-catalogs: nil
687 sgml-namecase-general:t