2 <!-- $Id: zoom.xml,v 1.17 2006-10-10 21:59:43 adam Exp $ -->
3 <title>ZOOM-C++</title>
6 <sect1 id="zoom-introduction">
7 <title>Introduction</title>
9 <ulink url="&url.zoom;">ZOOM</ulink>
10 is the emerging standard API for information retrieval programming
11 using the Z39.50 protocol. ZOOM's
12 <ulink url="&url.zoom.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="&url.zoom.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="&url.zoom.bind.cplusplus;">C++ binding</ulink>
22 for ZOOM, enabling quick, easy development of client applications.
25 For example, here is a tiny Z39.50 client that fetches and displays
26 the MARC record for Farlow & Brett Surman's
27 <citetitle>The Complete Dinosaur</citetitle>
28 from the Library of Congress's Z39.50 server:
31 #include <iostream>
32 #include <yazpp/zoom.h>
36 int main(int argc, char **argv)
38 connection conn("z3950.loc.gov", 7090);
39 conn.option("databaseName", "Voyager");
40 conn.option("preferredRecordSyntax", "USMARC");
41 resultSet rs(conn, prefixQuery("@attr 1=7 0253333490"));
42 const record *rec = rs.getRecord(0);
43 cout << rec->render() << endl;
48 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>.)
54 YAZ++'s implementation of the C++ binding is a thin layer over YAZ's
55 implementation of the C binding. For information on the supported
56 options and other such details, see the ZOOM-C documentation, which
57 can be found on-line at
58 <ulink url="&url.yaz.zoom;"/>
61 All of the classes defined by ZOOM-C++ are in the
62 <literal>ZOOM</literal> namespace. We will now consider
63 the five main classes in turn:
68 <literal>connection</literal>
74 <literal>query</literal> and its subclasses
75 <literal>prefixQuery</literal> and
76 <literal>CCLQuery</literal>
82 <literal>resultSet</literal>
88 <literal>record</literal>
94 <literal>exception</literal> and its subclasses
95 <literal>systemException</literal>,
96 <literal>bib1Exception</literal> and
97 <literal>queryException</literal>
105 <sect1 id="zoom-connection">
106 <title><literal>ZOOM::connection</literal></title>
108 A <literal>ZOOM::connection</literal> object represents an open
109 connection to a Z39.50 server. Such a connection is forged by
110 constructing a <literal>connection</literal> object.
113 The class has this declaration:
118 connection (const char *hostname, int portnum);
120 const char *option (const char *key) const;
121 const char *option (const char *key, const char *val);
125 When a new <literal>connection</literal> is created, the hostname
126 and port number of a Z39.50 server must be supplied, and the
127 network connection is forged and wrapped in the new object. If the
128 connection can't be established - perhaps because the hostname
129 couldn't be resolved, or there is no server listening on the
130 specified port - then an
131 <link linkend="zoom-exception"><literal>exception</literal></link>
135 The only other methods on a <literal>connection</literal> object
136 are for getting and setting options. Any name-value pair of
137 strings may be set as options, and subsequently retrieved, but
138 certain options have special meanings which are understood by the
139 ZOOM code and affect the behaviour of the object that carries
140 them. For example, the value of the
141 <literal>databaseName</literal> option is used as the name of the
142 database to query when a search is executed against the
143 <literal>connection</literal>. For a full list of such special
144 options, see the ZOOM abstract API and the ZOOM-C documentation
148 <sect2 id="connection.references">
149 <title>References</title>
153 <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.2"
154 >Section 3.2 (Connection) of the ZOOM Abstract API</ulink>
159 <ulink url="&url.yaz.zoom.connections;"
160 >The Connections section f the ZOOM-C documentation</ulink>
168 <sect1 id="zoom-query">
169 <title><literal>ZOOM::query</literal> and subclasses</title>
171 The <literal>ZOOM::query</literal> class is a virtual base class,
172 representing a query to be submitted to a server. This class has
173 no methods, but two (so far) concrete subclasses, each implementing
174 a specific query notation.
177 <sect2 id="ZOOM::prefixQuery">
178 <title><literal>ZOOM::prefixQuery</literal></title>
180 class prefixQuery : public query {
182 prefixQuery (const char *pqn);
187 This class enables a query to be created by compiling YAZ's
189 <ulink url="&url.yaz.pqf;">Prefix Query Notation (PQN)</ulink>.
193 <sect2 id="ZOOM::CCLQuery">
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="&url.yaz.ccl;">Common Command Language (CCL)</ulink>.
206 The qualifiers recognised by the CCL parser are specified in an
207 external configuration file in the format described by the YAZ
211 If query construction fails for either type of
212 <literal>query</literal> object - typically because the query
213 string itself is not valid PQN or CCL - then an
214 <link linkend="zoom-exception"><literal>exception</literal></link>
219 <sect2 id="queries.discussion">
220 <title>Discussion</title>
222 It will be readily recognised that these objects have no methods
223 other than their constructors: their only role in life is to be
224 used in searching, by being passed to the
225 <literal>resultSet</literal> class's constructor.
228 Given a suitable set of CCL qualifiers, the following pairs of
229 queries are equivalent:
232 prefixQuery("dinosaur");
233 CCLQuery("dinosaur");
235 prefixQuery("@and complete dinosaur");
236 CCLQuery("complete and dinosaur");
238 prefixQuery("@and complete @or dinosaur pterosaur");
239 CCLQuery("complete and (dinosaur or pterosaur)");
241 prefixQuery("@attr 1=7 0253333490");
242 CCLQuery("isbn=0253333490");
246 <sect2 id="query.references">
247 <title>References</title>
251 <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.3"
252 >Section 3.3 (Query) of the ZOOM Abstract API</ulink>
257 <ulink url="&url.yaz.zoom.query;"
258 >The Queries section of the ZOOM-C documentation</ulink>
266 <sect1 id="zoom-resultset">
267 <title><literal>ZOOM::resultSet</literal></title>
269 A <literal>ZOOM::resultSet</literal> object represents a set of
270 records identified by a query that has been executed against a
271 particular connection. The sole purpose of both
272 <literal>connection</literal> and <literal>query</literal> objects
273 is that they can be used to create new
274 <literal>resultSet</literal>s - that is, to perform a search on the
275 server on the remote end of the connection.
278 The class has this declaration:
283 resultSet (connection &c, const query &q);
285 const char *option (const char *key) const;
286 const char *option (const char *key, const char *val);
287 size_t size () const;
288 const record *getRecord (size_t i) const;
292 New <literal>resultSet</literal>s are created by the constructor,
293 which is passed a <literal>connection</literal>, indicating the
294 server on which the search is to be performed, and a
295 <literal>query</literal>, indicating what search to perform. If
296 the search fails - for example, because the query uses attributes
297 that the server doesn't implement - then an
298 <link linkend="zoom-exception"><literal>exception</literal></link>
302 Like <literal>connection</literal>s, <literal>resultSet</literal>
303 objects can carry name-value options. The special options which
304 affect ZOOM-C++'s behaviour are the same as those for ZOOM-C and
305 are described in its documentation (link below). In particular,
306 the <literal>preferredRecordSyntax</literal> option may be set to
307 a string such as ``USMARC'', ``SUTRS'' etc. to indicate what the
308 format in which records should be retrieved; and the
309 <literal>elementSetName</literal> option indicates whether brief
310 records (``B''), full records (``F'') or some other composition
314 The <literal>size()</literal> method returns the number of records
315 in the result set. Zero is a legitimate value: a search that finds
316 no records is not the same as a search that fails.
319 Finally, the <literal>getRecord</literal> method returns the
320 <parameter>i</parameter>th record from the result set, where
321 <parameter>i</parameter> is zero-based: that is, legitmate values
322 range from zero up to one less than the result-set size. If the
323 method fails, for example because the requested record is out of
324 range, it <literal>throw</literal>s an
325 <link linkend="zoom-exception"><literal>exception</literal></link>.
328 <sect2 id="resultset.references">
329 <title>References</title>
333 <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.4"
334 >Section 3.4 (Result Set) of the ZOOM Abstract API</ulink>
339 <ulink url="&url.yaz.zoom.resultsets;"
340 >The Result Sets section of the ZOOM-C documentation</ulink>
348 <sect1 id="zoom-record">
349 <title><literal>ZOOM::record</literal></title>
351 A <literal>ZOOM::record</literal> object represents a chunk of data
352 from a <literal>resultSet</literal> returned from a server.
355 The class has this declaration:
362 UNKNOWN, GRS1, SUTRS, USMARC, UKMARC, XML
364 record *clone () const;
365 syntax recsyn () const;
366 const char *render () const;
367 const char *rawdata () const;
371 Records returned from Z39.50 servers are encoded using a record
372 syntax: the various national MARC formats are commonly used for
373 bibliographic data, GRS-1 or XML for complex structured data, SUTRS
374 for simple human-readable text, etc. The
375 <literal>record::syntax</literal> enumeration specifies constants
376 representing common record syntaxes, and the
377 <literal>recsyn()</literal> method returns the value corresponding
378 to the record-syntax of the record on which it is invoked.
381 Because this interface uses an enumeration, it is difficult to
382 extend to other record syntaxes - for example, DANMARC, the MARC
383 variant widely used in Denmark. We might either grow the
384 enumeration substantially, or change the interface to return
385 either an integer or a string.
390 The simplest thing to do with a retrieved record is simply to
391 <literal>render()</literal> it. This returns a human-readable, but
392 not necessarily very pretty, representation of the contents of the
393 record. This is useful primarily for testing and debugging, since
394 the application has no control over how the record appears.
395 (The application must <emphasis>not</emphasis>
396 <literal>delete</literal> the returned string - it is ``owned'' by
400 More sophisticated applications will want to deal with the raw data
401 themselves: the <literal>rawdata()</literal> method returns it.
402 Its format will vary depending on the record syntax: SUTRS, MARC
403 and XML records are returned ``as is'', and GRS-1 records as a
404 pointer to their top-level node, which is a
405 <literal>Z_GenericRecord</literal> structure as defined in the
406 <literal><yaz/z-grs.h></literal> header file.
407 (The application must <emphasis>not</emphasis>
408 <literal>delete</literal> the returned data - it is ``owned'' by
412 Perceptive readers will notice that there are no methods for access
413 to individual fields within a record. That's because the different
414 record syntaxes are so different that there is no even a uniform
415 notion of what a field is across them all, let alone a sensible way
416 to implement such a function. Fetch the raw data instead, and pick
417 it apart ``by hand''.
420 <sect2 id="zoom.memory.management">
421 <title>Memory Management</title>
423 The <literal>record</literal> objects returned from
424 <literal>resultSet::getRecord()</literal> are ``owned'' by the
425 result set object: that means that the application is not
426 responsible for <literal>delete</literal>ing them - each
427 <literal>record</literal> is automatically deallocated when the
428 <literal>resultSet</literal> that owns it is
429 <literal>delete</literal>d.
432 Usually that's what you want: it means that you can easily fetch a
433 record, use it and forget all about it, like this:
436 resultSet rs(conn, query);
437 cout << rs.getRecord(0)->render();
440 But sometimes you want a <literal>record</literal> to live on past
441 the lifetime of the <literal>resultSet</literal> from which it was
442 fetched. In this case, the <literal>clone(f)</literal> method can
443 be used to make an autonomous copy. The application must
444 <literal>delete</literal> it when it doesn't need it any longer:
449 resultSet rs(conn, query);
450 rec = rs.getRecord(0)->clone();
451 // `rs' goes out of scope here, and is deleted
453 cout << rec->render();
458 <sect2 id="record.references">
459 <title>References</title>
463 <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.5"
464 >Section 3.5 (Record) of the ZOOM Abstract API</ulink>
469 <ulink url="&url.yaz.zoom.records;"
470 >The Records section of the ZOOM-C documentation</ulink>
478 <sect1 id="zoom-exception">
479 <title><literal>ZOOM::exception</literal> and subclasses</title>
481 The <literal>ZOOM::exception</literal> class is a virtual base
482 class, representing a diagnostic generated by the ZOOM-C++ library
483 or returned from a server. Its subclasses represent particular
487 When any of the ZOOM methods fail, they respond by
488 <literal>throw</literal>ing an object of type
489 <literal>exception</literal> or one of its subclasses. This most
490 usually happens with the <literal>connection</literal> constructor,
491 the various query constructors, the <literal>resultSet</literal>
492 constructor (which is actually the searching method) and
493 <literal>resultSet::getRecord()</literal>.
496 The base class has this declaration:
501 exception (int code);
502 int errcode () const;
503 const char *errmsg () const;
507 It has three concrete subclasses:
510 <sect2 id="ZOOM::systemException">
511 <title><literal>ZOOM::systemException</literal></title>
513 class systemException: public exception {
516 int errcode () const;
517 const char *errmsg () const;
521 Represents a ``system error'', typically indicating that a system
522 call failed - often in the low-level networking code that
523 underlies Z39.50. <literal>errcode()</literal> returns the value
524 that the system variable <literal>errno</literal> had at the time
525 the exception was constructed; and <literal>errmsg()</literal>
526 returns a human-readable error-message corresponidng to that error
531 <sect2 id="ZOOM::bib1Exception">
532 <title><literal>ZOOM::bib1Exception</literal></title>
534 class bib1Exception: public exception {
536 bib1Exception (int errcode, const char *addinfo);
537 int errcode () const;
538 const char *errmsg () const;
539 const char *addinfo () const;
543 Represents an error condition communicated by a Z39.50 server.
544 <literal>errcode()</literal> returns the BIB-1 diagnostic code of
545 the error, and <literal>errmsg()</literal> a human-readable error
546 message corresponding to that code. <literal>addinfo()</literal>
547 returns any additional information associated with the error.
550 For example, if a ZOOM application tries to search in the
551 ``Voyager'' database of a server that does not have a database of
552 that name, a <literal>bib1Exception</literal> will be thrown in
553 which <literal>errcode()</literal> returns 109,
554 <literal>errmsg()</literal> returns the corresponding error
555 message ``Database unavailable'' and <literal>addinfo()</literal>
556 returns the name of the requested, but unavailable, database.
560 <sect2 id="ZOOM::queryException">
561 <title><literal>ZOOM::queryException</literal></title>
563 class queryException: public exception {
565 static const int PREFIX = 1;
566 static const int CCL = 2;
567 queryException (int qtype, const char *source);
568 int errcode () const;
569 const char *errmsg () const;
570 const char *addinfo () const;
574 This class represents an error in parsing a query into a form that
575 a Z39.50 can understand. It must be created with the
576 <literal>qtype</literal> parameter equal to one of the query-type
577 constants, which can be retrieved via the
578 <literal>errcode()</literal> method; <literal>errmsg()</literal>
579 returns an error-message specifying which kind of query was
580 malformed; and <literal>addinfo()</literal> returns a copy of the
581 query itself (that is, the value of <literal>source</literal> with
582 which the exception object was created.)
586 <sect2 id="revised-sample">
587 <title>Revised Sample Program</title>
589 Now we can revise the sample program from the
590 <link linkend="zoom-introduction">introduction</link>
591 to catch exceptions and report any errors:
594 /* g++ -o zoom-c++-hw zoom-c++-hw.cpp -lzoompp -lyaz */
596 #include <iostream>
597 #include <yazpp/zoom.h>
599 using namespace ZOOM;
601 int main(int argc, char **argv)
604 connection conn("z3950.loc.gov", 7090);
605 conn.option("databaseName", "Voyager");
606 conn.option("preferredRecordSyntax", "USMARC");
607 resultSet rs(conn, prefixQuery("@attr 1=7 0253333490"));
608 const record *rec = rs.getRecord(0);
609 cout << rec->render() << endl;
610 } catch (systemException &e) {
611 cerr << "System error " <<
612 e.errcode() << " (" << e.errmsg() << ")" << endl;
613 } catch (bib1Exception &e) {
614 cerr << "BIB-1 error " <<
615 e.errcode() << " (" << e.errmsg() << "): " << e.addinfo() << endl;
616 } catch (queryException &e) {
617 cerr << "Query error " <<
618 e.errcode() << " (" << e.errmsg() << "): " << e.addinfo() << endl;
619 } catch (exception &e) {
620 cerr << "Error " <<
621 e.errcode() << " (" << e.errmsg() << ")" << endl;
626 The heart of this program is the same as in the original version,
627 but it's now wrapped in a <literal>try</literal> block followed by
628 several <literal>catch</literal> blocks which try to give helpful
629 diagnostics if something goes wrong.
632 The first such block diagnoses system-level errors such as memory
633 exhaustion or a network connection being broken by a server's
634 untimely death; the second catches errors at the Z39.50 level,
635 such as a server's report that it can't provide records in USMARC
636 syntax; the third is there in case there's something wrong with
637 the syntax of the query (although in this case it's correct); and
638 finally, the last <literal>catch</literal> block is a
639 belt-and-braces measure to be sure that nothing escapes us.
643 <sect2 id="exception.references">
644 <title>References</title>
648 <ulink url="http://zoom.z3950.org/api/zoom-1.3.html#3.7"
649 >Section 3.7 (Exception) of the ZOOM Abstract API</ulink>
654 <ulink url="&url.z39.50.diagnostics;">Bib-1 Diagnostics</ulink> on the
655 <ulink url="&url.z39.50;">Z39.50 Maintenance Agency</ulink> site.
660 Because C does not support exceptions, ZOOM-C has no API element
661 that corresponds directly with ZOOM-C++'s
662 <literal>exception</literal> class and its subclasses. The
663 closest thing is the <literal>ZOOM_connection_error</literal>
664 function described in
665 <ulink url="&url.yaz.zoom.connections;"
666 >The Connections section</ulink> of the documentation.
673 <!-- Keep this comment at the end of the file
678 sgml-minimize-attributes:nil
679 sgml-always-quote-attributes:t
682 sgml-parent-document: "yazpp.xml"
683 sgml-local-catalogs: nil
684 sgml-namecase-general:t