# SOAP and SRW

## Introduction

&yaz; uses a very simple implementation of SOAP that only, currenly, supports what is sufficient to offer SRW functionality. The implementation uses the tree API of libxml2 to encode and decode SOAP packages.

Like the Z39.50 ASN.1 module, the &yaz; SRW 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 SRW, 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.

## SRW

SRW is just one implementation of a SOAP handler as described in the previous section. The encoder/decoder handler for SRW 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;