2 <title>ZOOM-C++</title>
5 <sect1 id="zoom-introduction">
6 <title>Introduction</title>
8 <ulink url="&url.zoom;">ZOOM</ulink>
9 is the emerging standard API for information retrieval programming
10 using the Z39.50 protocol. ZOOM's
11 <ulink url="&url.zoom.api;">Abstract API</ulink>
12 specifies semantics for classes representing key IR concepts such as
13 connections, queries, result sets and records; and there are various
14 <ulink url="&url.zoom.bind;">bindings</ulink>
15 specifying how those concepts should be represented in various
16 programming languages.
19 The YAZ++ library includes an implementation of the <ulink
20 url="&url.zoom.bind.cplusplus;">C++ binding</ulink>
21 for ZOOM, enabling quick, easy development of client applications.
24 For example, here is a tiny Z39.50 client that fetches and displays
25 the MARC record for Farlow & Brett Surman's
26 <citetitle>The Complete Dinosaur</citetitle>
27 from the Library of Congress's Z39.50 server:
30 #include <iostream>
31 #include <yazpp/zoom.h>
35 int main(int argc, char **argv)
37 connection conn("z3950.loc.gov", 7090);
38 conn.option("databaseName", "Voyager");
39 conn.option("preferredRecordSyntax", "USMARC");
40 resultSet rs(conn, prefixQuery("@attr 1=7 0253333490"));
41 const record *rec = rs.getRecord(0);
42 cout << rec->render() << endl;
47 For the sake of simplicity, this program does not check
48 for errors: we show a more robust version of the same program
49 <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="&url.yaz.zoom;"/>
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
147 <sect2 id="connection.references">
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="&url.yaz.zoom.connections;"
159 >The Connections section f 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.
176 <sect2 id="ZOOM::prefixQuery">
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="&url.yaz.pqf;">Prefix Query Notation (PQN)</ulink>.
192 <sect2 id="ZOOM::CCLQuery">
193 <title><literal>ZOOM::CCLQuery</literal></title>
195 class CCLQuery : public query {
197 CCLQuery (const char *ccl, void *qualset);
202 This class enables a query to be created using the simpler but
204 <ulink url="&url.yaz.ccl;">Common Command Language (CCL)</ulink>.
205 The qualifiers recognised by the CCL parser are specified in an
206 external configuration file in the format described by the YAZ
210 If query construction fails for either type of
211 <literal>query</literal> object - typically because the query
212 string itself is not valid PQN or CCL - then an
213 <link linkend="zoom-exception"><literal>exception</literal></link>
218 <sect2 id="queries.discussion">
219 <title>Discussion</title>
221 It will be readily recognised that these objects have no methods
222 other than their constructors: their only role in life is to be
223 used in searching, by being passed to the
224 <literal>resultSet</literal> class's constructor.
227 Given a suitable set of CCL qualifiers, the following pairs of
228 queries are equivalent:
231 prefixQuery("dinosaur");
232 CCLQuery("dinosaur");
234 prefixQuery("@and complete dinosaur");
235 CCLQuery("complete and dinosaur");
237 prefixQuery("@and complete @or dinosaur pterosaur");
238 CCLQuery("complete and (dinosaur or pterosaur)");
240 prefixQuery("@attr 1=7 0253333490");
241 CCLQuery("isbn=0253333490");
245 <sect2 id="query.references">
246 <title>References</title>
250 <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.3"
251 >Section 3.3 (Query) of the ZOOM Abstract API</ulink>
256 <ulink url="&url.yaz.zoom.query;"
257 >The Queries section of the ZOOM-C documentation</ulink>
265 <sect1 id="zoom-resultset">
266 <title><literal>ZOOM::resultSet</literal></title>
268 A <literal>ZOOM::resultSet</literal> object represents a set of
269 records identified by a query that has been executed against a
270 particular connection. The sole purpose of both
271 <literal>connection</literal> and <literal>query</literal> objects
272 is that they can be used to create new
273 <literal>resultSet</literal>s - that is, to perform a search on the
274 server on the remote end of the connection.
277 The class has this declaration:
282 resultSet (connection &c, const query &q);
284 const char *option (const char *key) const;
285 const char *option (const char *key, const char *val);
286 size_t size () const;
287 const record *getRecord (size_t i) const;
291 New <literal>resultSet</literal>s are created by the constructor,
292 which is passed a <literal>connection</literal>, indicating the
293 server on which the search is to be performed, and a
294 <literal>query</literal>, indicating what search to perform. If
295 the search fails - for example, because the query uses attributes
296 that the server doesn't implement - then an
297 <link linkend="zoom-exception"><literal>exception</literal></link>
301 Like <literal>connection</literal>s, <literal>resultSet</literal>
302 objects can carry name-value options. The special options which
303 affect ZOOM-C++'s behaviour are the same as those for ZOOM-C and
304 are described in its documentation (link below). In particular,
305 the <literal>preferredRecordSyntax</literal> option may be set to
306 a string such as ``USMARC'', ``SUTRS'' etc. to indicate what the
307 format in which records should be retrieved; and the
308 <literal>elementSetName</literal> option indicates whether brief
309 records (``B''), full records (``F'') or some other composition
313 The <literal>size()</literal> method returns the number of records
314 in the result set. Zero is a legitimate value: a search that finds
315 no records is not the same as a search that fails.
318 Finally, the <literal>getRecord</literal> method returns the
319 <parameter>i</parameter>th record from the result set, where
320 <parameter>i</parameter> is zero-based: that is, legitmate values
321 range from zero up to one less than the result-set size. If the
322 method fails, for example because the requested record is out of
323 range, it <literal>throw</literal>s an
324 <link linkend="zoom-exception"><literal>exception</literal></link>.
327 <sect2 id="resultset.references">
328 <title>References</title>
332 <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.4"
333 >Section 3.4 (Result Set) of the ZOOM Abstract API</ulink>
338 <ulink url="&url.yaz.zoom.resultsets;"
339 >The Result Sets section of the ZOOM-C documentation</ulink>
347 <sect1 id="zoom-record">
348 <title><literal>ZOOM::record</literal></title>
350 A <literal>ZOOM::record</literal> object represents a chunk of data
351 from a <literal>resultSet</literal> returned from a server.
354 The class has this declaration:
361 UNKNOWN, GRS1, SUTRS, USMARC, UKMARC, XML
363 record *clone () const;
364 syntax recsyn () const;
365 const char *render () const;
366 const char *rawdata () const;
370 Records returned from Z39.50 servers are encoded using a record
371 syntax: the various national MARC formats are commonly used for
372 bibliographic data, GRS-1 or XML for complex structured data, SUTRS
373 for simple human-readable text, etc. The
374 <literal>record::syntax</literal> enumeration specifies constants
375 representing common record syntaxes, and the
376 <literal>recsyn()</literal> method returns the value corresponding
377 to the record-syntax of the record on which it is invoked.
380 Because this interface uses an enumeration, it is difficult to
381 extend to other record syntaxes - for example, DANMARC, the MARC
382 variant widely used in Denmark. We might either grow the
383 enumeration substantially, or change the interface to return
384 either an integer or a string.
389 The simplest thing to do with a retrieved record is simply to
390 <literal>render()</literal> it. This returns a human-readable, but
391 not necessarily very pretty, representation of the contents of the
392 record. This is useful primarily for testing and debugging, since
393 the application has no control over how the record appears.
394 (The application must <emphasis>not</emphasis>
395 <literal>delete</literal> the returned string - it is ``owned'' by
399 More sophisticated applications will want to deal with the raw data
400 themselves: the <literal>rawdata()</literal> method returns it.
401 Its format will vary depending on the record syntax: SUTRS, MARC
402 and XML records are returned ``as is'', and GRS-1 records as a
403 pointer to their top-level node, which is a
404 <literal>Z_GenericRecord</literal> structure as defined in the
405 <literal><yaz/z-grs.h></literal> header file.
406 (The application must <emphasis>not</emphasis>
407 <literal>delete</literal> the returned data - it is ``owned'' by
411 Perceptive readers will notice that there are no methods for access
412 to individual fields within a record. That's because the different
413 record syntaxes are so different that there is no even a uniform
414 notion of what a field is across them all, let alone a sensible way
415 to implement such a function. Fetch the raw data instead, and pick
416 it apart ``by hand''.
419 <sect2 id="zoom.memory.management">
420 <title>Memory Management</title>
422 The <literal>record</literal> objects returned from
423 <literal>resultSet::getRecord()</literal> are ``owned'' by the
424 result set object: that means that the application is not
425 responsible for <literal>delete</literal>ing them - each
426 <literal>record</literal> is automatically deallocated when the
427 <literal>resultSet</literal> that owns it is
428 <literal>delete</literal>d.
431 Usually that's what you want: it means that you can easily fetch a
432 record, use it and forget all about it, like this:
435 resultSet rs(conn, query);
436 cout << rs.getRecord(0)->render();
439 But sometimes you want a <literal>record</literal> to live on past
440 the lifetime of the <literal>resultSet</literal> from which it was
441 fetched. In this case, the <literal>clone(f)</literal> method can
442 be used to make an autonomous copy. The application must
443 <literal>delete</literal> it when it doesn't need it any longer:
448 resultSet rs(conn, query);
449 rec = rs.getRecord(0)->clone();
450 // `rs' goes out of scope here, and is deleted
452 cout << rec->render();
457 <sect2 id="record.references">
458 <title>References</title>
462 <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.5"
463 >Section 3.5 (Record) of the ZOOM Abstract API</ulink>
468 <ulink url="&url.yaz.zoom.records;"
469 >The Records section of the ZOOM-C documentation</ulink>
477 <sect1 id="zoom-exception">
478 <title><literal>ZOOM::exception</literal> and subclasses</title>
480 The <literal>ZOOM::exception</literal> class is a virtual base
481 class, representing a diagnostic generated by the ZOOM-C++ library
482 or returned from a server. Its subclasses represent particular
486 When any of the ZOOM methods fail, they respond by
487 <literal>throw</literal>ing an object of type
488 <literal>exception</literal> or one of its subclasses. This most
489 usually happens with the <literal>connection</literal> constructor,
490 the various query constructors, the <literal>resultSet</literal>
491 constructor (which is actually the searching method) and
492 <literal>resultSet::getRecord()</literal>.
495 The base class has this declaration:
500 exception (int code);
501 int errcode () const;
502 const char *errmsg () const;
506 It has three concrete subclasses:
509 <sect2 id="ZOOM::systemException">
510 <title><literal>ZOOM::systemException</literal></title>
512 class systemException: public exception {
515 int errcode () const;
516 const char *errmsg () const;
520 Represents a ``system error'', typically indicating that a system
521 call failed - often in the low-level networking code that
522 underlies Z39.50. <literal>errcode()</literal> returns the value
523 that the system variable <literal>errno</literal> had at the time
524 the exception was constructed; and <literal>errmsg()</literal>
525 returns a human-readable error-message corresponidng to that error
530 <sect2 id="ZOOM::bib1Exception">
531 <title><literal>ZOOM::bib1Exception</literal></title>
533 class bib1Exception: public exception {
535 bib1Exception (int errcode, const char *addinfo);
536 int errcode () const;
537 const char *errmsg () const;
538 const char *addinfo () const;
542 Represents an error condition communicated by a Z39.50 server.
543 <literal>errcode()</literal> returns the BIB-1 diagnostic code of
544 the error, and <literal>errmsg()</literal> a human-readable error
545 message corresponding to that code. <literal>addinfo()</literal>
546 returns any additional information associated with the error.
549 For example, if a ZOOM application tries to search in the
550 ``Voyager'' database of a server that does not have a database of
551 that name, a <literal>bib1Exception</literal> will be thrown in
552 which <literal>errcode()</literal> returns 109,
553 <literal>errmsg()</literal> returns the corresponding error
554 message ``Database unavailable'' and <literal>addinfo()</literal>
555 returns the name of the requested, but unavailable, database.
559 <sect2 id="ZOOM::queryException">
560 <title><literal>ZOOM::queryException</literal></title>
562 class queryException: public exception {
564 static const int PREFIX = 1;
565 static const int CCL = 2;
566 queryException (int qtype, const char *source);
567 int errcode () const;
568 const char *errmsg () const;
569 const char *addinfo () const;
573 This class represents an error in parsing a query into a form that
574 a Z39.50 can understand. It must be created with the
575 <literal>qtype</literal> parameter equal to one of the query-type
576 constants, which can be retrieved via the
577 <literal>errcode()</literal> method; <literal>errmsg()</literal>
578 returns an error-message specifying which kind of query was
579 malformed; and <literal>addinfo()</literal> returns a copy of the
580 query itself (that is, the value of <literal>source</literal> with
581 which the exception object was created.)
585 <sect2 id="revised-sample">
586 <title>Revised Sample Program</title>
588 Now we can revise the sample program from the
589 <link linkend="zoom-introduction">introduction</link>
590 to catch exceptions and report any errors:
593 /* g++ -o zoom-c++-hw zoom-c++-hw.cpp -lzoompp -lyaz */
595 #include <iostream>
596 #include <yazpp/zoom.h>
598 using namespace ZOOM;
600 int main(int argc, char **argv)
603 connection conn("z3950.loc.gov", 7090);
604 conn.option("databaseName", "Voyager");
605 conn.option("preferredRecordSyntax", "USMARC");
606 resultSet rs(conn, prefixQuery("@attr 1=7 0253333490"));
607 const record *rec = rs.getRecord(0);
608 cout << rec->render() << endl;
609 } catch (systemException &e) {
610 cerr << "System error " <<
611 e.errcode() << " (" << e.errmsg() << ")" << endl;
612 } catch (bib1Exception &e) {
613 cerr << "BIB-1 error " <<
614 e.errcode() << " (" << e.errmsg() << "): " << e.addinfo() << endl;
615 } catch (queryException &e) {
616 cerr << "Query error " <<
617 e.errcode() << " (" << e.errmsg() << "): " << e.addinfo() << endl;
618 } catch (exception &e) {
619 cerr << "Error " <<
620 e.errcode() << " (" << e.errmsg() << ")" << endl;
625 The heart of this program is the same as in the original version,
626 but it's now wrapped in a <literal>try</literal> block followed by
627 several <literal>catch</literal> blocks which try to give helpful
628 diagnostics if something goes wrong.
631 The first such block diagnoses system-level errors such as memory
632 exhaustion or a network connection being broken by a server's
633 untimely death; the second catches errors at the Z39.50 level,
634 such as a server's report that it can't provide records in USMARC
635 syntax; the third is there in case there's something wrong with
636 the syntax of the query (although in this case it's correct); and
637 finally, the last <literal>catch</literal> block is a
638 belt-and-braces measure to be sure that nothing escapes us.
642 <sect2 id="exception.references">
643 <title>References</title>
647 <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.7"
648 >Section 3.7 (Exception) of the ZOOM Abstract API</ulink>
653 <ulink url="&url.z39.50.diagnostics;">Bib-1 Diagnostics</ulink> on the
654 <ulink url="&url.z39.50;">Z39.50 Maintenance Agency</ulink> site.
659 Because C does not support exceptions, ZOOM-C has no API element
660 that corresponds directly with ZOOM-C++'s
661 <literal>exception</literal> class and its subclasses. The
662 closest thing is the <literal>ZOOM_connection_error</literal>
663 function described in
664 <ulink url="&url.yaz.zoom.connections;"
665 >The Connections section</ulink> of the documentation.
672 <!-- Keep this comment at the end of the file
677 sgml-minimize-attributes:nil
678 sgml-always-quote-attributes:t
681 sgml-parent-document: "yazpp.xml"
682 sgml-local-catalogs: nil
683 sgml-namecase-general:t