2 <!-- $Id: zoom.xml,v 1.14 2006-04-24 12:47:34 marc 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 <yazpp/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;
49 For the sake of simplicity, this program does not check
50 for errors: we show a more robust version of the same program
51 <link linkend="revised-sample">later</link>.)
55 YAZ++'s implementation of the C++ binding is a thin layer over YAZ's
56 implementation of the C binding. For information on the supported
57 options and other such details, see the ZOOM-C documentation, which
58 can be found on-line at
59 <ulink url="http://www.indexdata.dk/yaz/doc/zoom.tkl"/>
62 All of the classes defined by ZOOM-C++ are in the
63 <literal>ZOOM</literal> namespace. We will now consider
64 the five main classes in turn:
69 <literal>connection</literal>
75 <literal>query</literal> and its subclasses
76 <literal>prefixQuery</literal> and
77 <literal>CCLQuery</literal>
83 <literal>resultSet</literal>
89 <literal>record</literal>
95 <literal>exception</literal> and its subclasses
96 <literal>systemException</literal>,
97 <literal>bib1Exception</literal> and
98 <literal>queryException</literal>
106 <sect1 id="zoom-connection">
107 <title><literal>ZOOM::connection</literal></title>
109 A <literal>ZOOM::connection</literal> object represents an open
110 connection to a Z39.50 server. Such a connection is forged by
111 constructing a <literal>connection</literal> object.
114 The class has this declaration:
119 connection (const char *hostname, int portnum);
121 const char *option (const char *key) const;
122 const char *option (const char *key, const char *val);
126 When a new <literal>connection</literal> is created, the hostname
127 and port number of a Z39.50 server must be supplied, and the
128 network connection is forged and wrapped in the new object. If the
129 connection can't be established - perhaps because the hostname
130 couldn't be resolved, or there is no server listening on the
131 specified port - then an
132 <link linkend="zoom-exception"><literal>exception</literal></link>
136 The only other methods on a <literal>connection</literal> object
137 are for getting and setting options. Any name-value pair of
138 strings may be set as options, and subsequently retrieved, but
139 certain options have special meanings which are understood by the
140 ZOOM code and affect the behaviour of the object that carries
141 them. For example, the value of the
142 <literal>databaseName</literal> option is used as the name of the
143 database to query when a search is executed against the
144 <literal>connection</literal>. For a full list of such special
145 options, see the ZOOM abstract API and the ZOOM-C documentation
150 <title>References</title>
154 <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.2"
155 >Section 3.2 (Connection) of the ZOOM Abstract API</ulink>
160 <ulink url="http://www.indexdata.dk/yaz/doc/zoom.tkl#zoom.connections"
161 >The Connections section of the ZOOM-C documentation</ulink>
169 <sect1 id="zoom-query">
170 <title><literal>ZOOM::query</literal> and subclasses</title>
172 The <literal>ZOOM::query</literal> class is a virtual base class,
173 representing a query to be submitted to a server. This class has
174 no methods, but two (so far) concrete subclasses, each implementing
175 a specific query notation.
179 <title><literal>ZOOM::prefixQuery</literal></title>
181 class prefixQuery : public query {
183 prefixQuery (const char *pqn);
188 This class enables a query to be created by compiling YAZ's
190 <ulink url="http://www.indexdata.dk/yaz/doc/tools.tkl#PQF"
191 >Prefix Query Notation (PQN)</ulink>.
196 <title><literal>ZOOM::CCLQuery</literal></title>
198 class CCLQuery : public query {
200 CCLQuery (const char *ccl, void *qualset);
205 This class enables a query to be created using the simpler but
207 <ulink url="http://www.indexdata.dk/yaz/doc/tools.tkl#CCL"
208 >Common Command Language (CCL)</ulink>.
209 The qualifiers recognised by the CCL parser are specified in an
210 external configuration file in the format described by the YAZ
214 If query construction fails for either type of
215 <literal>query</literal> object - typically because the query
216 string itself is not valid PQN or CCL - then an
217 <link linkend="zoom-exception"><literal>exception</literal></link>
223 <title>Discussion</title>
225 It will be readily recognised that these objects have no methods
226 other than their constructors: their only role in life is to be
227 used in searching, by being passed to the
228 <literal>resultSet</literal> class's constructor.
231 Given a suitable set of CCL qualifiers, the following pairs of
232 queries are equivalent:
235 prefixQuery("dinosaur");
236 CCLQuery("dinosaur");
238 prefixQuery("@and complete dinosaur");
239 CCLQuery("complete and dinosaur");
241 prefixQuery("@and complete @or dinosaur pterosaur");
242 CCLQuery("complete and (dinosaur or pterosaur)");
244 prefixQuery("@attr 1=7 0253333490");
245 CCLQuery("isbn=0253333490");
250 <title>References</title>
254 <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.3"
255 >Section 3.3 (Query) of the ZOOM Abstract API</ulink>
260 <ulink url="http://www.indexdata.dk/yaz/doc/zoom.query.tkl"
261 >The Queries section of the ZOOM-C documentation</ulink>
269 <sect1 id="zoom-resultset">
270 <title><literal>ZOOM::resultSet</literal></title>
272 A <literal>ZOOM::resultSet</literal> object represents a set of
273 records identified by a query that has been executed against a
274 particular connection. The sole purpose of both
275 <literal>connection</literal> and <literal>query</literal> objects
276 is that they can be used to create new
277 <literal>resultSet</literal>s - that is, to perform a search on the
278 server on the remote end of the connection.
281 The class has this declaration:
286 resultSet (connection &c, const query &q);
288 const char *option (const char *key) const;
289 const char *option (const char *key, const char *val);
290 size_t size () const;
291 const record *getRecord (size_t i) const;
295 New <literal>resultSet</literal>s are created by the constructor,
296 which is passed a <literal>connection</literal>, indicating the
297 server on which the search is to be performed, and a
298 <literal>query</literal>, indicating what search to perform. If
299 the search fails - for example, because the query uses attributes
300 that the server doesn't implement - then an
301 <link linkend="zoom-exception"><literal>exception</literal></link>
305 Like <literal>connection</literal>s, <literal>resultSet</literal>
306 objects can carry name-value options. The special options which
307 affect ZOOM-C++'s behaviour are the same as those for ZOOM-C and
308 are described in its documentation (link below). In particular,
309 the <literal>preferredRecordSyntax</literal> option may be set to
310 a string such as ``USMARC'', ``SUTRS'' etc. to indicate what the
311 format in which records should be retrieved; and the
312 <literal>elementSetName</literal> option indicates whether brief
313 records (``B''), full records (``F'') or some other composition
317 The <literal>size()</literal> method returns the number of records
318 in the result set. Zero is a legitimate value: a search that finds
319 no records is not the same as a search that fails.
322 Finally, the <literal>getRecord</literal> method returns the
323 <parameter>i</parameter>th record from the result set, where
324 <parameter>i</parameter> is zero-based: that is, legitmate values
325 range from zero up to one less than the result-set size. If the
326 method fails, for example because the requested record is out of
327 range, it <literal>throw</literal>s an
328 <link linkend="zoom-exception"><literal>exception</literal></link>.
332 <title>References</title>
336 <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.4"
337 >Section 3.4 (Result Set) of the ZOOM Abstract API</ulink>
342 <ulink url="http://www.indexdata.dk/yaz/doc/zoom.resultsets.tkl"
343 >The Result Sets section of the ZOOM-C documentation</ulink>
351 <sect1 id="zoom-record">
352 <title><literal>ZOOM::record</literal></title>
354 A <literal>ZOOM::record</literal> object represents a chunk of data
355 from a <literal>resultSet</literal> returned from a server.
358 The class has this declaration:
365 UNKNOWN, GRS1, SUTRS, USMARC, UKMARC, XML
367 record *clone () const;
368 syntax recsyn () const;
369 const char *render () const;
370 const char *rawdata () const;
374 Records returned from Z39.50 servers are encoded using a record
375 syntax: the various national MARC formats are commonly used for
376 bibliographic data, GRS-1 or XML for complex structured data, SUTRS
377 for simple human-readable text, etc. The
378 <literal>record::syntax</literal> enumeration specifies constants
379 representing common record syntaxes, and the
380 <literal>recsyn()</literal> method returns the value corresponding
381 to the record-syntax of the record on which it is invoked.
384 Because this interface uses an enumeration, it is difficult to
385 extend to other record syntaxes - for example, DANMARC, the MARC
386 variant widely used in Denmark. We might either grow the
387 enumeration substantially, or change the interface to return
388 either an integer or a string.
393 The simplest thing to do with a retrieved record is simply to
394 <literal>render()</literal> it. This returns a human-readable, but
395 not necessarily very pretty, representation of the contents of the
396 record. This is useful primarily for testing and debugging, since
397 the application has no control over how the record appears.
398 (The application must <emphasis>not</emphasis>
399 <literal>delete</literal> the returned string - it is ``owned'' by
403 More sophisticated applications will want to deal with the raw data
404 themselves: the <literal>rawdata()</literal> method returns it.
405 Its format will vary depending on the record syntax: SUTRS, MARC
406 and XML records are returned ``as is'', and GRS-1 records as a
407 pointer to their top-level node, which is a
408 <literal>Z_GenericRecord</literal> structure as defined in the
409 <literal><yaz/z-grs.h></literal> header file.
410 (The application must <emphasis>not</emphasis>
411 <literal>delete</literal> the returned data - it is ``owned'' by
415 Perceptive readers will notice that there are no methods for access
416 to individual fields within a record. That's because the different
417 record syntaxes are so different that there is no even a uniform
418 notion of what a field is across them all, let alone a sensible way
419 to implement such a function. Fetch the raw data instead, and pick
420 it apart ``by hand''.
424 <title>Memory Management</title>
426 The <literal>record</literal> objects returned from
427 <literal>resultSet::getRecord()</literal> are ``owned'' by the
428 result set object: that means that the application is not
429 responsible for <literal>delete</literal>ing them - each
430 <literal>record</literal> is automatically deallocated when the
431 <literal>resultSet</literal> that owns it is
432 <literal>delete</literal>d.
435 Usually that's what you want: it means that you can easily fetch a
436 record, use it and forget all about it, like this:
439 resultSet rs(conn, query);
440 cout << rs.getRecord(0)->render();
443 But sometimes you want a <literal>record</literal> to live on past
444 the lifetime of the <literal>resultSet</literal> from which it was
445 fetched. In this case, the <literal>clone(f)</literal> method can
446 be used to make an autonomous copy. The application must
447 <literal>delete</literal> it when it doesn't need it any longer:
452 resultSet rs(conn, query);
453 rec = rs.getRecord(0)->clone();
454 // `rs' goes out of scope here, and is deleted
456 cout << rec->render();
462 <title>References</title>
466 <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.5"
467 >Section 3.5 (Record) of the ZOOM Abstract API</ulink>
472 <ulink url="http://www.indexdata.dk/yaz/doc/zoom.records.tkl"
473 >The Records section of the ZOOM-C documentation</ulink>
481 <sect1 id="zoom-exception">
482 <title><literal>ZOOM::exception</literal> and subclasses</title>
484 The <literal>ZOOM::exception</literal> class is a virtual base
485 class, representing a diagnostic generated by the ZOOM-C++ library
486 or returned from a server. Its subclasses represent particular
490 When any of the ZOOM methods fail, they respond by
491 <literal>throw</literal>ing an object of type
492 <literal>exception</literal> or one of its subclasses. This most
493 usually happens with the <literal>connection</literal> constructor,
494 the various query constructors, the <literal>resultSet</literal>
495 constructor (which is actually the searching method) and
496 <literal>resultSet::getRecord()</literal>.
499 The base class has this declaration:
504 exception (int code);
505 int errcode () const;
506 const char *errmsg () const;
510 It has three concrete subclasses:
514 <title><literal>ZOOM::systemException</literal></title>
516 class systemException: public exception {
519 int errcode () const;
520 const char *errmsg () const;
524 Represents a ``system error'', typically indicating that a system
525 call failed - often in the low-level networking code that
526 underlies Z39.50. <literal>errcode()</literal> returns the value
527 that the system variable <literal>errno</literal> had at the time
528 the exception was constructed; and <literal>errmsg()</literal>
529 returns a human-readable error-message corresponidng to that error
535 <title><literal>ZOOM::bib1Exception</literal></title>
537 class bib1Exception: public exception {
539 bib1Exception (int errcode, const char *addinfo);
540 int errcode () const;
541 const char *errmsg () const;
542 const char *addinfo () const;
546 Represents an error condition communicated by a Z39.50 server.
547 <literal>errcode()</literal> returns the BIB-1 diagnostic code of
548 the error, and <literal>errmsg()</literal> a human-readable error
549 message corresponding to that code. <literal>addinfo()</literal>
550 returns any additional information associated with the error.
553 For example, if a ZOOM application tries to search in the
554 ``Voyager'' database of a server that does not have a database of
555 that name, a <literal>bib1Exception</literal> will be thrown in
556 which <literal>errcode()</literal> returns 109,
557 <literal>errmsg()</literal> returns the corresponding error
558 message ``Database unavailable'' and <literal>addinfo()</literal>
559 returns the name of the requested, but unavailable, database.
564 <title><literal>ZOOM::queryException</literal></title>
566 class queryException: public exception {
568 static const int PREFIX = 1;
569 static const int CCL = 2;
570 queryException (int qtype, const char *source);
571 int errcode () const;
572 const char *errmsg () const;
573 const char *addinfo () const;
577 This class represents an error in parsing a query into a form that
578 a Z39.50 can understand. It must be created with the
579 <literal>qtype</literal> parameter equal to one of the query-type
580 constants, which can be retrieved via the
581 <literal>errcode()</literal> method; <literal>errmsg()</literal>
582 returns an error-message specifying which kind of query was
583 malformed; and <literal>addinfo()</literal> returns a copy of the
584 query itself (that is, the value of <literal>source</literal> with
585 which the exception object was created.)
589 <sect2 id="revised-sample">
590 <title>Revised Sample Program</title>
592 Now we can revise the sample program from the
593 <link linkend="zoom-introduction">introduction</link>
594 to catch exceptions and report any errors:
597 /* g++ -o zoom-c++-hw zoom-c++-hw.cpp -lzoompp -lyaz */
599 #include <iostream>
600 #include <yazpp/zoom.h>
602 using namespace ZOOM;
604 int main(int argc, char **argv)
607 connection conn("z3950.loc.gov", 7090);
608 conn.option("databaseName", "Voyager");
609 conn.option("preferredRecordSyntax", "USMARC");
610 resultSet rs(conn, prefixQuery("@attr 1=7 0253333490"));
611 const record *rec = rs.getRecord(0);
612 cout << rec->render() << endl;
613 } catch (systemException &e) {
614 cerr << "System error " <<
615 e.errcode() << " (" << e.errmsg() << ")" << endl;
616 } catch (bib1Exception &e) {
617 cerr << "BIB-1 error " <<
618 e.errcode() << " (" << e.errmsg() << "): " << e.addinfo() << endl;
619 } catch (queryException &e) {
620 cerr << "Query error " <<
621 e.errcode() << " (" << e.errmsg() << "): " << e.addinfo() << endl;
622 } catch (exception &e) {
623 cerr << "Error " <<
624 e.errcode() << " (" << e.errmsg() << ")" << endl;
629 The heart of this program is the same as in the original version,
630 but it's now wrapped in a <literal>try</literal> block followed by
631 several <literal>catch</literal> blocks which try to give helpful
632 diagnostics if something goes wrong.
635 The first such block diagnoses system-level errors such as memory
636 exhaustion or a network connection being broken by a server's
637 untimely death; the second catches errors at the Z39.50 level,
638 such as a server's report that it can't provide records in USMARC
639 syntax; the third is there in case there's something wrong with
640 the syntax of the query (although in this case it's correct); and
641 finally, the last <literal>catch</literal> block is a
642 belt-and-braces measure to be sure that nothing escapes us.
647 <title>References</title>
651 <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.7"
652 >Section 3.7 (Exception) of the ZOOM Abstract API</ulink>
657 <ulink url="http://lcweb.loc.gov/z3950/agency/defns/bib1diag.html"
658 >Bib-1 Diagnostics</ulink> on the
659 <ulink url="http://lcweb.loc.gov/z3950/agency/"
660 >Z39.50 Maintenance Agency</ulink> site.
665 Because C does not support exceptions, ZOOM-C has no API element
666 that corresponds directly with ZOOM-C++'s
667 <literal>exception</literal> class and its subclasses. The
668 closest thing is the <literal>ZOOM_connection_error</literal>
669 function described in
670 <ulink url="http://www.indexdata.dk/yaz/doc/zoom.tkl#zoom.connections"
671 >The Connections section</ulink> of the documentation.
678 <!-- Keep this Emacs mode comment at the end of the file