SOAP and SRU Introduction &yaz; uses a very simple implementation of SOAP that only, currenly, supports what is sufficient to offer SRU SOAP functionality. The implementation uses the tree API of libxml2 to encode and decode SOAP packages. Like the Z39.50 ASN.1 module, the &yaz; SRU implementation uses simple C structs to represent SOAP packages as well as HTTP packages. HTTP &yaz; only offers HTTP as transport carrier for SOAP, but it is relatively easy to change that. The following definition of Z_GDU (Generic Data Unit) allows for both HTTP and Z39.50 in one packet. #include <yaz/zgdu.h> #define Z_GDU_Z3950 1 #define Z_GDU_HTTP_Request 2 #define Z_GDU_HTTP_Response 3 typedef struct { int which; union { Z_APDU *z3950; Z_HTTP_Request *HTTP_Request; Z_HTTP_Response *HTTP_Response; } u; } Z_GDU ; The corresponding Z_GDU encoder/decoder is z_GDU. The z3950 is any of the known BER encoded Z39.50 APDUs. HTTP_Request and HTTP_Response is the HTTP Request and Response respectively. SOAP Packages Every SOAP package in &yaz; is represented as follows: #include <yaz/soap.h> typedef struct { char *fault_code; char *fault_string; char *details; } Z_SOAP_Fault; typedef struct { int no; char *ns; void *p; } Z_SOAP_Generic; #define Z_SOAP_fault 1 #define Z_SOAP_generic 2 #define Z_SOAP_error 3 typedef struct { int which; union { Z_SOAP_Fault *fault; Z_SOAP_Generic *generic; Z_SOAP_Fault *soap_error; } u; const char *ns; } Z_SOAP; The fault and soap_error arms represent both a SOAP fault - struct Z_SOAP_Fault. Any other generic (valid) package is represented by Z_SOAP_Generic. The ns as part of Z_SOAP is the namespace for SOAP itself and reflects the SOAP version. For version 1.1 it is http://schemas.xmlsoap.org/soap/envelope/, for version 1.2 it is http://www.w3.org/2001/06/soap-envelope. int z_soap_codec(ODR o, Z_SOAP **pp, char **content_buf, int *content_len, Z_SOAP_Handler *handlers); The content_buf and content_len is XML buffer and length of buffer respectively. The handlers is a list of SOAP codec handlers - one handler for each service namespace. For SRU SOAP, the namespace would be http://www.loc.gov/zing/srw/v1.0/. When decoding, the z_soap_codec inspects the XML content and tries to match one of the services namespaces of the supplied handlers. If there is a match a handler function is invoked which decodes that particular SOAP package. If successful, the returned Z_SOAP package will be of type Z_SOAP_Generic. Member no is set the offset of handler that matched; ns is set to namespace of matching handler; the void pointer p is set to the C data structure assocatiated with the handler. When a NULL namespace is met (member ns bwlow), that specifies end-of-list. Each handler is defined as follows: typedef struct { char *ns; void *client_data; Z_SOAP_fun f; } Z_SOAP_Handler; The ns is namespace of service associated with handler f. client_data is user-defined data which is passed to handler. The prototype for a SOAP service handler is: int handler(ODR o, void * ptr, void **handler_data, void *client_data, const char *ns); The o specifies the mode (decode/encode) as usual. The second argument, ptr, is a libxml2 tree node pointer (xmlNodePtr) and is a pointer to the Body element of the SOAP package. The handler_data is an opaque pointer to a C definitions associated with the SOAP service. client_data is the pointer which was set as part of the Z_SOAP_handler. Finally, ns the service namespace. SRU SRU SOAP is just one implementation of a SOAP handler as described in the previous section. The encoder/decoder handler for SRU is defined as follows: #include <yaz/srw.h> int yaz_srw_codec(ODR o, void * pptr, Z_SRW_GDU **handler_data, void *client_data, const char *ns); Here, Z_SRW_GDU is either searchRetrieveRequest or a searchRetrieveResponse. The xQuery and xSortKeys are not handled yet by the SRW implementation of &yaz;. Explain is also missing. Future versions of &yaz; will include these features. The definition of searchRetrieveRequest is: typedef struct { #define Z_SRW_query_type_cql 1 #define Z_SRW_query_type_xcql 2 #define Z_SRW_query_type_pqf 3 int query_type; union { char *cql; char *xcql; char *pqf; } query; #define Z_SRW_sort_type_none 1 #define Z_SRW_sort_type_sort 2 #define Z_SRW_sort_type_xSort 3 int sort_type; union { char *none; char *sortKeys; char *xSortKeys; } sort; int *startRecord; int *maximumRecords; char *recordSchema; char *recordPacking; char *database; } Z_SRW_searchRetrieveRequest; Please observe that data of type xsd:string is represented as a char pointer (char *). A null pointer means that the element is absent. Data of type xsd:integer is representd as a pointer to an int (int *). Again, a null pointer us used for absent elements. The SearchRetrieveResponse has the following definition. typedef struct { int * numberOfRecords; char * resultSetId; int * resultSetIdleTime; Z_SRW_record *records; int num_records; Z_SRW_diagnostic *diagnostics; int num_diagnostics; int *nextRecordPosition; } Z_SRW_searchRetrieveResponse; The num_records and num_diagnostics is number of returned records and diagnostics respectively and also correspond to the "size of" arrays records and diagnostics. A retrieval record is defined as follows: typedef struct { char *recordSchema; char *recordData_buf; int recordData_len; int *recordPosition; } Z_SRW_record; The record data is defined as a buffer of some length so that data can be of any type. SRW 1.0 currenly doesn't allow for this (only XML), but future versions might do. And, a diagnostic as: typedef struct { int *code; char *details; } Z_SRW_diagnostic;