Added ZiNG Update Support. New codecs are defined in srw.h. Extended the
[yaz-moved-to-github.git] / src / srw.c
1 /*
2  * Copyright (C) 1995-2005, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: srw.c,v 1.37 2005-11-08 15:08:02 adam Exp $
6  */
7 /**
8  * \file srw.c
9  * \brief Implements SRW/SRU package encoding and decoding
10  */
11
12 #include <yaz/srw.h>
13 #if HAVE_XML2
14 #include <libxml/parser.h>
15 #include <libxml/tree.h>
16
17 static void add_XML_n(xmlNodePtr ptr, const char *elem, char *val, int len)
18 {
19     if (val)
20     {
21         xmlDocPtr doc = xmlParseMemory(val,len);
22         if (doc)
23         {
24             xmlNodePtr c = xmlNewChild(ptr, 0, BAD_CAST elem, 0);
25             xmlNodePtr t = xmlDocGetRootElement(doc);
26             xmlAddChild(c, xmlCopyNode(t,1));
27             xmlFreeDoc(doc);
28         }
29     }
30 }
31
32 xmlNodePtr add_xsd_string_n(xmlNodePtr ptr, const char *elem, const char *val,
33                             int len)
34 {
35     if (val)
36     {
37         xmlNodePtr c = xmlNewChild(ptr, 0, BAD_CAST elem, 0);
38         xmlNodePtr t = xmlNewTextLen(BAD_CAST val, len);
39         xmlAddChild(c, t);
40         return t;
41     }
42     return 0;
43 }
44
45 xmlNodePtr add_xsd_string(xmlNodePtr ptr, const char *elem, const char *val)
46 {
47     if (val)
48         return xmlNewTextChild(ptr, 0, BAD_CAST elem,
49                                BAD_CAST val);
50     return 0;
51 }
52
53 static void add_xsd_integer(xmlNodePtr ptr, const char *elem, const int *val)
54 {
55     if (val)
56     {
57         char str[30];
58         sprintf(str, "%d", *val);
59         xmlNewTextChild(ptr, 0, BAD_CAST elem, BAD_CAST str);
60     }
61 }
62
63 static int match_element(xmlNodePtr ptr, const char *elem)
64 {
65     if (ptr->type == XML_ELEMENT_NODE && !xmlStrcmp(ptr->name, BAD_CAST elem))
66         return 1;
67     return 0;
68 }
69
70 #define CHECK_TYPE 0
71
72 static int match_xsd_string_n(xmlNodePtr ptr, const char *elem, ODR o,
73                               char **val, int *len)
74 {
75 #if CHECK_TYPE
76     struct _xmlAttr *attr;
77 #endif
78     if (!match_element(ptr, elem))
79         return 0;
80 #if CHECK_TYPE
81     for (attr = ptr->properties; attr; attr = attr->next)
82         if (!strcmp(attr->name, "type") &&
83             attr->children && attr->children->type == XML_TEXT_NODE)
84         {
85             const char *t = strchr(attr->children->content, ':');
86             if (t)
87                 t = t + 1;
88             else
89                 t = attr->children->content;
90             if (!strcmp(t, "string"))
91                 break;
92         }
93     if (!attr)
94         return 0;
95 #endif
96     ptr = ptr->children;
97     if (!ptr || ptr->type != XML_TEXT_NODE)
98     {
99         *val = "";
100         return 1;
101     }
102     *val = odr_strdup(o, (const char *) ptr->content);
103     if (len)
104         *len = xmlStrlen(ptr->content);
105     return 1;
106 }
107
108
109 static int match_xsd_string(xmlNodePtr ptr, const char *elem, ODR o,
110                             char **val)
111 {
112     return match_xsd_string_n(ptr, elem, o, val, 0);
113 }
114
115 static int match_xsd_XML_n(xmlNodePtr ptr, const char *elem, ODR o,
116                            char **val, int *len)
117 {
118     xmlBufferPtr buf;
119
120     if (!match_element(ptr, elem))
121         return 0;
122     ptr = ptr->children;
123     while (ptr && (ptr->type == XML_TEXT_NODE || ptr->type == XML_COMMENT_NODE))
124         ptr = ptr->next;
125     if (!ptr)
126         return 0;
127     buf = xmlBufferCreate();
128     
129     xmlNodeDump(buf, ptr->doc, ptr, 0, 0);
130     
131     *val = odr_malloc(o, buf->use+1);
132     memcpy (*val, buf->content, buf->use);
133     (*val)[buf->use] = '\0';
134
135     if (len)
136         *len = buf->use;
137
138     xmlBufferFree(buf);
139
140     return 1;
141 }
142                      
143 static int match_xsd_integer(xmlNodePtr ptr, const char *elem, ODR o, int **val)
144 {
145 #if CHECK_TYPE
146     struct _xmlAttr *attr;
147 #endif
148     if (!match_element(ptr, elem))
149         return 0;
150 #if CHECK_TYPE
151     for (attr = ptr->properties; attr; attr = attr->next)
152         if (!strcmp(attr->name, "type") &&
153             attr->children && attr->children->type == XML_TEXT_NODE)
154         {
155             const char *t = strchr(attr->children->content, ':');
156             if (t)
157                 t = t + 1;
158             else
159                 t = attr->children->content;
160             if (!strcmp(t, "integer"))
161                 break;
162         }
163     if (!attr)
164         return 0;
165 #endif
166     ptr = ptr->children;
167     if (!ptr || ptr->type != XML_TEXT_NODE)
168         return 0;
169     *val = odr_intdup(o, atoi((const char *) ptr->content));
170     return 1;
171 }
172
173 static int yaz_srw_extra_record(ODR o, xmlNodePtr pptr,
174                                 Z_SRW_extra_record *rec,
175                                 void *client_data, const char *ns)
176 {
177     if (o->direction == ODR_DECODE)
178     {
179         xmlNodePtr ptr;
180         rec->type = 1;
181         rec->recordId         = 0;
182         rec->recordReviewCode = 0;
183         rec->recordReviewNote = 0;
184         rec->recordLockStatus = 0;
185         rec->recordOldVersion = 0;
186         rec->nonDupRecordId   = 0;
187         for (ptr = pptr->children; ptr; ptr = ptr->next)
188         {
189             if (match_xsd_string(ptr, "recordId", o, 
190                                  &rec->recordId ))
191                 ;
192             else if (match_xsd_string(ptr, "recordReviewCode", o, 
193                                       &rec->recordReviewCode ))
194               ;
195             else if (match_xsd_string(ptr, "recordReviewNote", o, 
196                                        &rec->recordReviewNote ))
197                 ;
198             else if (match_xsd_string(ptr, "nonDupRecordId", o, 
199                                       &rec->nonDupRecordId ))
200               ;
201             else if (match_xsd_string(ptr, "recordLockStatus", o, 
202                                       &rec->recordLockStatus ))
203               ;
204             else if (match_xsd_string(ptr, "recordOldVersion", o, 
205                                       &rec->recordOldVersion ))
206               ;
207         }
208     }
209     else if (o->direction == ODR_ENCODE)
210     {
211         xmlNodePtr ptr = pptr;
212         if ( rec->recordId )
213             add_xsd_string(ptr, "recordId", rec->recordId);
214         if ( rec->recordReviewCode )
215             add_xsd_string(ptr, "recordReviewCode", rec->recordReviewCode);
216         if (  rec->recordReviewNote )
217             add_xsd_string(ptr, "recordReviewNote", rec->recordReviewNote);
218         if ( rec->nonDupRecordId ) 
219             add_xsd_string(ptr, "nonDupRecordId", rec->nonDupRecordId);
220         if ( rec->recordLockStatus ) 
221             add_xsd_string(ptr, "recordLockStatus", rec->recordLockStatus);
222         if (  rec->recordOldVersion )
223             add_xsd_string(ptr, "recordOldVersion", rec->recordOldVersion);
224     }
225     return 0;
226 }
227
228 static int yaz_srw_record(ODR o, xmlNodePtr pptr, Z_SRW_record *rec,
229                           Z_SRW_extra_record **extra,
230                           void *client_data, const char *ns)
231 {
232     if (o->direction == ODR_DECODE)
233     {
234         char *spack = 0;
235         int pack = Z_SRW_recordPacking_string;
236         xmlNodePtr ptr;
237         xmlNodePtr data_ptr;
238         rec->recordSchema = 0;
239         rec->recordData_buf = 0;
240         rec->recordData_len = 0;
241         rec->recordPosition = 0;
242         *extra = 0;
243         for (ptr = pptr->children; ptr; ptr = ptr->next)
244         {
245             
246             if (match_xsd_string(ptr, "recordSchema", o, 
247                                  &rec->recordSchema)){
248             }
249             else if (match_xsd_string(ptr, "recordPacking", o, &spack))
250             {
251                 if (spack && !strcmp(spack, "xml"))
252                     pack = Z_SRW_recordPacking_XML;
253                 if (spack && !strcmp(spack, "url"))
254                     pack = Z_SRW_recordPacking_URL;
255                 if (spack && !strcmp(spack, "string"))
256                     pack = Z_SRW_recordPacking_string;
257             }
258             else if (match_xsd_integer(ptr, "recordPosition", o, 
259                                        &rec->recordPosition))
260                 ;
261             else if (match_element(ptr, "recordData")){
262                 /* save position of Data until after the loop
263                    then we will know the packing (hopefully), and
264                    unpacking is done once
265                 */
266                 data_ptr = ptr;
267             }
268             else if (match_element(ptr, "extraRecordData")){
269                 *extra = (Z_SRW_extra_record *)
270                     odr_malloc(o, sizeof(Z_SRW_extra_record));
271                 yaz_srw_extra_record(o, ptr, *extra, client_data, ns);
272             }
273         }
274         switch(pack)
275         {
276         case Z_SRW_recordPacking_XML:
277             match_xsd_XML_n(data_ptr, "recordData", o, 
278                             &rec->recordData_buf, &rec->recordData_len);
279             break;
280         case Z_SRW_recordPacking_URL:
281             /* just store it as a string.
282                leave it to the backend to collect the document */
283             match_xsd_string_n(ptr, "recordData", o, 
284                                &rec->recordData_buf, &rec->recordData_len);
285             break;
286         case Z_SRW_recordPacking_string:
287             match_xsd_string_n(ptr, "recordData", o, 
288                                &rec->recordData_buf, &rec->recordData_len);
289             break;
290         default:
291             rec->recordData_buf = 0;
292             rec->recordData_len = 0;
293             /* need some way to signal diagnostic here */
294         }
295         rec->recordPacking = pack;
296     }
297     else if (o->direction == ODR_ENCODE)
298     {
299         xmlNodePtr ptr = pptr;
300         int pack = rec->recordPacking;
301         add_xsd_string(ptr, "recordSchema", rec->recordSchema);
302
303         switch(pack)
304         {
305         case Z_SRW_recordPacking_string:
306             add_xsd_string(ptr, "recordPacking", "string");
307             add_xsd_string_n(ptr, "recordData", rec->recordData_buf,
308                              rec->recordData_len);
309             break;
310         case Z_SRW_recordPacking_XML:
311             add_xsd_string(ptr, "recordPacking", "xml");
312             add_XML_n(ptr, "recordData", rec->recordData_buf,
313                       rec->recordData_len);
314             break;
315         case Z_SRW_recordPacking_URL:
316             add_xsd_string(ptr, "recordPacking", "url");
317             add_xsd_string_n(ptr, "recordData", rec->recordData_buf,
318                              rec->recordData_len);
319             break;
320         }
321         if (rec->recordPosition)
322             add_xsd_integer(ptr, "recordPosition", rec->recordPosition );
323         if (*extra)
324         {
325             xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "extraRecordData",
326                                           0);
327             yaz_srw_extra_record(o, rptr, *extra, client_data, ns);
328         }
329     }
330     return 0;
331 }
332
333 static int yaz_srw_records(ODR o, xmlNodePtr pptr, Z_SRW_record **recs,
334                            Z_SRW_extra_record ***extra,
335                            int *num, void *client_data, const char *ns)
336 {
337     if (o->direction == ODR_DECODE)
338     {
339         int i;
340         xmlNodePtr ptr;
341         *num = 0;
342         for (ptr = pptr->children; ptr; ptr = ptr->next)
343         {
344             if (ptr->type == XML_ELEMENT_NODE &&
345                 !xmlStrcmp(ptr->name, BAD_CAST "record"))
346                 (*num)++;
347         }
348         if (!*num)
349             return 1;
350         *recs = (Z_SRW_record *) odr_malloc(o, *num * sizeof(**recs));
351         *extra = (Z_SRW_extra_record **) odr_malloc(o, *num * sizeof(**extra));
352         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next)
353         {
354             if (ptr->type == XML_ELEMENT_NODE &&
355                 !xmlStrcmp(ptr->name, BAD_CAST "record"))
356             {
357                 yaz_srw_record(o, ptr, *recs + i, *extra + i, client_data, ns);
358                 i++;
359             }
360         }
361     }
362     else if (o->direction == ODR_ENCODE)
363     {
364         int i;
365         for (i = 0; i < *num; i++)
366         {
367             xmlNodePtr rptr = xmlNewChild(pptr, 0, BAD_CAST "record",
368                                           0);
369             yaz_srw_record(o, rptr, (*recs)+i, *extra + i, client_data, ns);
370         }
371     }
372     return 0;
373 }
374
375 static int yaz_srw_diagnostics(ODR o, xmlNodePtr pptr, Z_SRW_diagnostic **recs,
376                                int *num, void *client_data, const char *ns)
377 {
378     if (o->direction == ODR_DECODE)
379     {
380         int i;
381         xmlNodePtr ptr;
382         *num = 0;
383         for (ptr = pptr->children; ptr; ptr = ptr->next)
384         {
385             if (ptr->type == XML_ELEMENT_NODE &&
386                 !xmlStrcmp(ptr->name, BAD_CAST "diagnostic"))
387                 (*num)++;
388         }
389         if (!*num)
390             return 1;
391         *recs = (Z_SRW_diagnostic *) odr_malloc(o, *num * sizeof(**recs));
392         for (i = 0; i < *num; i++)
393         {
394             (*recs)[i].uri = 0;
395             (*recs)[i].details = 0;
396             (*recs)[i].message = 0;
397         } 
398         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next)
399         {
400             if (ptr->type == XML_ELEMENT_NODE &&
401                 !xmlStrcmp(ptr->name, BAD_CAST "diagnostic"))
402             {
403                 xmlNodePtr rptr;
404                 (*recs)[i].uri = 0;
405                 (*recs)[i].details = 0;
406                 (*recs)[i].message = 0;
407                 for (rptr = ptr->children; rptr; rptr = rptr->next)
408                 {
409                     if (match_xsd_string(rptr, "uri", o, 
410                                          &(*recs)[i].uri))
411                         ;
412                     else if (match_xsd_string(rptr, "details", o, 
413                                               &(*recs)[i].details))
414                         ;
415                     else if (match_xsd_string(rptr, "message", o, 
416                                               &(*recs)[i].message))
417                         ;
418                 }
419                 i++;
420             }
421         }
422     }
423     else if (o->direction == ODR_ENCODE)
424     {
425         int i;
426         xmlNsPtr ns_diag =
427             xmlNewNs(pptr, BAD_CAST
428                      "http://www.loc.gov/zing/srw/diagnostic/", 0);
429         for (i = 0; i < *num; i++)
430         {
431             const char *std_diag = "info:srw/diagnostic/1/";
432             xmlNodePtr rptr = xmlNewChild(pptr, ns_diag,
433                                           BAD_CAST "diagnostic", 0);
434             add_xsd_string(rptr, "uri", (*recs)[i].uri);
435             if ((*recs)[i].message)
436                 add_xsd_string(rptr, "message", (*recs)[i].message);
437             else if ((*recs)[i].uri && 
438                      !strncmp((*recs)[i].uri, std_diag, strlen(std_diag)))
439             {
440                 int no = atoi((*recs)[i].uri + strlen(std_diag));
441                 const char *message = yaz_diag_srw_str(no);
442                 if (message)
443                     add_xsd_string(rptr, "message", message);
444             }
445             add_xsd_string(rptr, "details", (*recs)[i].details);
446         }
447     }
448     return 0;
449 }
450
451 static int yaz_srw_term(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm *term,
452                         void *client_data, const char *ns)
453 {
454     if (o->direction == ODR_DECODE)
455     {
456         xmlNodePtr ptr;
457         term->value = 0;
458         term->numberOfRecords = 0;
459         term->displayTerm = 0;
460         term->whereInList = 0;
461         for (ptr = pptr->children; ptr; ptr = ptr->next)
462         {
463             if (match_xsd_string(ptr, "value", o,  &term->value))
464                 ;
465             else if (match_xsd_integer(ptr, "numberOfRecords", o, 
466                                    &term->numberOfRecords))
467                 ;
468             else if (match_xsd_string(ptr, "displayTerm", o, 
469                                       &term->displayTerm))
470                 ;
471             else if (match_xsd_string(ptr, "whereInList", o, 
472                                       &term->whereInList))
473                 ;
474         }
475     }
476     else if (o->direction == ODR_ENCODE)
477     {
478         xmlNodePtr ptr = pptr;
479         add_xsd_string(ptr, "value", term->value);
480         add_xsd_integer(ptr, "numberOfRecords", term->numberOfRecords);
481         add_xsd_string(ptr, "displayTerm", term->displayTerm);
482         add_xsd_string(ptr, "whereInList", term->whereInList);
483     }
484     return 0;
485 }
486
487 static int yaz_srw_terms(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm **terms,
488                          int *num, void *client_data, const char *ns)
489 {
490     if (o->direction == ODR_DECODE)
491     {
492         int i;
493         xmlNodePtr ptr;
494         *num = 0;
495         for (ptr = pptr->children; ptr; ptr = ptr->next)
496         {
497             if (ptr->type == XML_ELEMENT_NODE &&
498                 !xmlStrcmp(ptr->name, BAD_CAST "term"))
499                 (*num)++;
500         }
501         if (!*num)
502             return 1;
503         *terms = (Z_SRW_scanTerm *) odr_malloc(o, *num * sizeof(**terms));
504         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
505         {
506             if (ptr->type == XML_ELEMENT_NODE &&
507                 !xmlStrcmp(ptr->name, BAD_CAST "term"))
508                 yaz_srw_term(o, ptr, (*terms)+i, client_data, ns);
509         }
510     }
511     else if (o->direction == ODR_ENCODE)
512     {
513         int i;
514         for (i = 0; i < *num; i++)
515         {
516             xmlNodePtr rptr = xmlNewChild(pptr, 0, BAD_CAST "term", 0);
517             yaz_srw_term(o, rptr, (*terms)+i, client_data, ns);
518         }
519     }
520     return 0;
521 }
522
523 int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
524                   void *client_data, const char *ns)
525 {
526     xmlNodePtr pptr = (xmlNodePtr) vptr;
527     if (o->direction == ODR_DECODE)
528     {
529         Z_SRW_PDU **p = handler_data;
530         xmlNodePtr method = pptr->children;
531
532         while (method && method->type == XML_TEXT_NODE)
533             method = method->next;
534         
535         if (!method)
536             return -1;
537         if (method->type != XML_ELEMENT_NODE)
538             return -1;
539
540         *p = (Z_SRW_PDU *) odr_malloc(o, sizeof(**p));
541         (*p)->srw_version = odr_strdup(o, "1.1");
542         
543         if (!xmlStrcmp(method->name, BAD_CAST "searchRetrieveRequest"))
544         {
545             xmlNodePtr ptr = method->children;
546             Z_SRW_searchRetrieveRequest *req;
547
548             (*p)->which = Z_SRW_searchRetrieve_request;
549             req = (*p)->u.request = (Z_SRW_searchRetrieveRequest *)
550                 odr_malloc(o, sizeof(*req));
551             req->query_type = Z_SRW_query_type_cql;
552             req->query.cql = 0;
553             req->sort_type = Z_SRW_sort_type_none;
554             req->sort.none = 0;
555             req->startRecord = 0;
556             req->maximumRecords = 0;
557             req->recordSchema = 0;
558             req->recordPacking = 0;
559             req->recordXPath = 0;
560             req->resultSetTTL = 0;
561             req->stylesheet = 0;
562             req->database = 0;
563
564             for (; ptr; ptr = ptr->next)
565             {
566                 if (match_xsd_string(ptr, "version", o,
567                                      &(*p)->srw_version))
568                     ;
569                 else if (match_xsd_string(ptr, "query", o, 
570                                      &req->query.cql))
571                     req->query_type = Z_SRW_query_type_cql;
572                 else if (match_xsd_string(ptr, "pQuery", o, 
573                                      &req->query.pqf))
574                     req->query_type = Z_SRW_query_type_pqf;
575                 else if (match_xsd_string(ptr, "xQuery", o, 
576                                      &req->query.xcql))
577                     req->query_type = Z_SRW_query_type_xcql;
578                 else if (match_xsd_integer(ptr, "startRecord", o,
579                                            &req->startRecord))
580                     ;
581                 else if (match_xsd_integer(ptr, "maximumRecords", o,
582                                            &req->maximumRecords))
583                     ;
584                 else if (match_xsd_string(ptr, "recordPacking", o,
585                                           &req->recordPacking))
586                     ;
587                 else if (match_xsd_string(ptr, "recordSchema", o, 
588                                           &req->recordSchema))
589                     ;
590                 else if (match_xsd_string(ptr, "recordXPath", o,
591                                           &req->recordXPath))
592                     ;
593                 else if (match_xsd_string(ptr, "resultSetTTL", o,
594                                            &req->database))
595                     ;
596                 else if (match_xsd_string(ptr, "sortKeys", o, 
597                                           &req->sort.sortKeys))
598                     req->sort_type = Z_SRW_sort_type_sort;
599                 else if (match_xsd_string(ptr, "stylesheet", o,
600                                            &req->stylesheet))
601                     ;
602                 else if (match_xsd_string(ptr, "database", o,
603                                            &req->database))
604                     ;
605                 /* missing is xQuery, xSortKeys .. */
606             }
607         }
608         else if (!xmlStrcmp(method->name, BAD_CAST "searchRetrieveResponse"))
609         {
610             xmlNodePtr ptr = method->children;
611             Z_SRW_searchRetrieveResponse *res;
612
613             (*p)->which = Z_SRW_searchRetrieve_response;
614             res = (*p)->u.response = (Z_SRW_searchRetrieveResponse *)
615                 odr_malloc(o, sizeof(*res));
616
617             res->numberOfRecords = 0;
618             res->resultSetId = 0;
619             res->resultSetIdleTime = 0;
620             res->records = 0;
621             res->num_records = 0;
622             res->diagnostics = 0;
623             res->num_diagnostics = 0;
624             res->nextRecordPosition = 0;
625
626             for (; ptr; ptr = ptr->next)
627             {
628                 if (match_xsd_string(ptr, "version", o,
629                                      &(*p)->srw_version))
630                     ;
631                 else if (match_xsd_integer(ptr, "numberOfRecords", o, 
632                                       &res->numberOfRecords))
633                     ;
634                 else if (match_xsd_string(ptr, "resultSetId", o, 
635                                           &res->resultSetId))
636                     ;
637                 else if (match_xsd_integer(ptr, "resultSetIdleTime", o, 
638                                            &res->resultSetIdleTime))
639                     ;
640                 else if (match_element(ptr, "records"))
641                     yaz_srw_records(o, ptr, &res->records,
642                                     &res->extra_records, 
643                                     &res->num_records, client_data, ns);
644                 else if (match_xsd_integer(ptr, "nextRecordPosition", o,
645                                            &res->nextRecordPosition))
646                     ;
647                 else if (match_element(ptr, "diagnostics"))
648                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
649                                         &res->num_diagnostics,
650                                         client_data, ns);
651             }
652         }
653         else if (!xmlStrcmp(method->name, BAD_CAST "explainRequest"))
654         {
655             Z_SRW_explainRequest *req;
656             xmlNodePtr ptr = method->children;
657             
658             (*p)->which = Z_SRW_explain_request;
659             req = (*p)->u.explain_request = (Z_SRW_explainRequest *)
660                 odr_malloc(o, sizeof(*req));
661             req->recordPacking = 0;
662             req->database = 0;
663             req->stylesheet = 0;
664             for (; ptr; ptr = ptr->next)
665             {
666                 if (match_xsd_string(ptr, "version", o,
667                                            &(*p)->srw_version))
668                     ;
669                 else if (match_xsd_string(ptr, "stylesheet", o,
670                                           &req->stylesheet))
671                     ;
672                 else if (match_xsd_string(ptr, "recordPacking", o,
673                                      &req->recordPacking))
674                     ;
675                 else if (match_xsd_string(ptr, "database", o,
676                                      &req->database))
677                     ;
678             }
679         }
680         else if (!xmlStrcmp(method->name, BAD_CAST "explainResponse"))
681         {
682             Z_SRW_explainResponse *res;
683             xmlNodePtr ptr = method->children;
684
685             (*p)->which = Z_SRW_explain_response;
686             res = (*p)->u.explain_response = (Z_SRW_explainResponse*)
687                 odr_malloc(o, sizeof(*res));
688             res->diagnostics = 0;
689             res->num_diagnostics = 0;
690             res->record.recordSchema = 0;
691             res->record.recordData_buf = 0;
692             res->record.recordData_len = 0;
693             res->record.recordPosition = 0;
694
695             for (; ptr; ptr = ptr->next)
696             {
697                 if (match_xsd_string(ptr, "version", o,
698                                            &(*p)->srw_version))
699                     ;
700                 else if (match_element(ptr, "record"))
701                     yaz_srw_record(o, ptr, &res->record, &res->extra_record,
702                                    client_data, ns);
703                 else if (match_element(ptr, "diagnostics"))
704                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
705                                         &res->num_diagnostics,
706                                         client_data, ns);
707                 ;
708             }
709         }
710         else if (!xmlStrcmp(method->name, BAD_CAST "scanRequest"))
711         {
712             Z_SRW_scanRequest *req;
713             xmlNodePtr ptr = method->children;
714
715             (*p)->which = Z_SRW_scan_request;
716             req = (*p)->u.scan_request = (Z_SRW_scanRequest *)
717                 odr_malloc(o, sizeof(*req));
718             req->query_type = Z_SRW_query_type_cql;
719             req->scanClause.cql = 0;
720             req->responsePosition = 0;
721             req->maximumTerms = 0;
722             req->stylesheet = 0;
723             req->database = 0;
724             
725             for (; ptr; ptr = ptr->next)
726             {
727                 if (match_xsd_string(ptr, "version", o,
728                                      &(*p)->srw_version))
729                     ;
730                 else if (match_xsd_string(ptr, "scanClause", o,
731                                      &req->scanClause.cql))
732                     ;
733                 else if (match_xsd_string(ptr, "pScanClause", o,
734                                           &req->scanClause.pqf))
735                 {
736                     req->query_type = Z_SRW_query_type_pqf;
737                 }
738                 else if (match_xsd_integer(ptr, "responsePosition", o,
739                                            &req->responsePosition))
740                     ;
741                 else if (match_xsd_integer(ptr, "maximumTerms", o,
742                                            &req->maximumTerms))
743                     ;
744                 else if (match_xsd_string(ptr, "stylesheet", o,
745                                           &req->stylesheet))
746                     ;
747                 else if (match_xsd_string(ptr, "database", o,
748                                           &req->database))
749                     ;
750             }
751         }
752         else if (!xmlStrcmp(method->name, BAD_CAST "scanResponse"))
753         {
754             Z_SRW_scanResponse *res;
755             xmlNodePtr ptr = method->children;
756
757             (*p)->which = Z_SRW_scan_response;
758             res = (*p)->u.scan_response = (Z_SRW_scanResponse *)
759                 odr_malloc(o, sizeof(*res));
760             res->terms = 0;
761             res->num_terms = 0;
762             res->diagnostics = 0;
763             res->num_diagnostics = 0;
764             
765             for (; ptr; ptr = ptr->next)
766             {
767                 if (match_xsd_string(ptr, "version", o,
768                                      &(*p)->srw_version))
769                     ;
770                 else if (match_element(ptr, "terms"))
771                     yaz_srw_terms(o, ptr, &res->terms,
772                                   &res->num_terms, client_data,
773                                   ns);
774                 else if (match_element(ptr, "diagnostics"))
775                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
776                                         &res->num_diagnostics,
777                                         client_data, ns);
778             }
779         }
780         else
781         {
782             *p = 0;
783             return -1;
784         }
785     }
786     else if (o->direction == ODR_ENCODE)
787     {
788         Z_SRW_PDU **p = handler_data;
789         xmlNsPtr ns_srw;
790         
791         if ((*p)->which == Z_SRW_searchRetrieve_request)
792         {
793             Z_SRW_searchRetrieveRequest *req = (*p)->u.request;
794             xmlNodePtr ptr = xmlNewChild(pptr, 0,
795                                          BAD_CAST "searchRetrieveRequest", 0);
796             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
797             xmlSetNs(ptr, ns_srw);
798
799             if ((*p)->srw_version)
800                 add_xsd_string(ptr, "version", (*p)->srw_version);
801             switch(req->query_type)
802             {
803             case Z_SRW_query_type_cql:
804                 add_xsd_string(ptr, "query", req->query.cql);
805                 break;
806             case Z_SRW_query_type_xcql:
807                 add_xsd_string(ptr, "xQuery", req->query.xcql);
808                 break;
809             case Z_SRW_query_type_pqf:
810                 add_xsd_string(ptr, "pQuery", req->query.pqf);
811                 break;
812             }
813             add_xsd_integer(ptr, "startRecord", req->startRecord);
814             add_xsd_integer(ptr, "maximumRecords", req->maximumRecords);
815             add_xsd_string(ptr, "recordPacking", req->recordPacking);
816             add_xsd_string(ptr, "recordSchema", req->recordSchema);
817             add_xsd_string(ptr, "recordXPath", req->recordXPath);
818             add_xsd_integer(ptr, "resultSetTTL", req->resultSetTTL);
819             switch(req->sort_type)
820             {
821             case Z_SRW_sort_type_none:
822                 break;
823             case Z_SRW_sort_type_sort:
824                 add_xsd_string(ptr, "sortKeys", req->sort.sortKeys);
825                 break;
826             case Z_SRW_sort_type_xSort:
827                 add_xsd_string(ptr, "xSortKeys", req->sort.xSortKeys);
828                 break;
829             }
830             add_xsd_string(ptr, "stylesheet", req->stylesheet);
831             add_xsd_string(ptr, "database", req->database);
832         }
833         else if ((*p)->which == Z_SRW_searchRetrieve_response)
834         {
835             Z_SRW_searchRetrieveResponse *res = (*p)->u.response;
836             xmlNodePtr ptr = xmlNewChild(pptr, 0,
837                                          BAD_CAST "searchRetrieveResponse", 0);
838             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
839             xmlSetNs(ptr, ns_srw);
840
841             if ((*p)->srw_version)
842                 add_xsd_string(ptr, "version", (*p)->srw_version);
843             add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
844             add_xsd_string(ptr, "resultSetId", res->resultSetId);
845             add_xsd_integer(ptr, "resultSetIdleTime", res->resultSetIdleTime);
846             if (res->num_records)
847             {
848                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "records", 0);
849                 yaz_srw_records(o, rptr, &res->records, &res->extra_records,
850                                 &res->num_records,
851                                 client_data, ns);
852             }
853             add_xsd_integer(ptr, "nextRecordPosition",
854                             res->nextRecordPosition);
855             if (res->num_diagnostics)
856             {
857                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "diagnostics",
858                                               0);
859                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
860                                     &res->num_diagnostics, client_data, ns);
861             }
862         }
863         else if ((*p)->which == Z_SRW_explain_request)
864         {
865             Z_SRW_explainRequest *req = (*p)->u.explain_request;
866             xmlNodePtr ptr = xmlNewChild(pptr, 0, BAD_CAST "explainRequest",
867                                          0);
868             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
869             xmlSetNs(ptr, ns_srw);
870
871             add_xsd_string(ptr, "version", (*p)->srw_version);
872             add_xsd_string(ptr, "recordPacking", req->recordPacking);
873             add_xsd_string(ptr, "stylesheet", req->stylesheet);
874             add_xsd_string(ptr, "database", req->database);
875         }
876         else if ((*p)->which == Z_SRW_explain_response)
877         {
878             Z_SRW_explainResponse *res = (*p)->u.explain_response;
879             xmlNodePtr ptr = xmlNewChild(pptr, 0, BAD_CAST "explainResponse",
880                                          0);
881             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
882             xmlSetNs(ptr, ns_srw);
883
884             add_xsd_string(ptr, "version", (*p)->srw_version);
885             if (1)
886             {
887                 xmlNodePtr ptr1 = xmlNewChild(ptr, 0, BAD_CAST "record", 0);
888                 yaz_srw_record(o, ptr1, &res->record, &res->extra_record,
889                                client_data, ns);
890             }
891             if (res->num_diagnostics)
892             {
893                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "diagnostics",
894                                               0);
895                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
896                                     &res->num_diagnostics, client_data, ns);
897             }
898         }
899         else if ((*p)->which == Z_SRW_scan_request)
900         {
901             Z_SRW_scanRequest *req = (*p)->u.scan_request;
902             xmlNodePtr ptr = xmlNewChild(pptr, 0, BAD_CAST "scanRequest", 0);
903             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
904             xmlSetNs(ptr, ns_srw);
905
906             add_xsd_string(ptr, "version", (*p)->srw_version);
907             switch(req->query_type)
908             {
909             case Z_SRW_query_type_cql:
910                 add_xsd_string(ptr, "scanClause", req->scanClause.cql);
911                 break;
912             case Z_SRW_query_type_pqf:
913                 add_xsd_string(ptr, "pScanClause", req->scanClause.pqf);
914                 break;
915             }
916             add_xsd_integer(ptr, "responsePosition", req->responsePosition);
917             add_xsd_integer(ptr, "maximumTerms", req->maximumTerms);
918             add_xsd_string(ptr, "stylesheet", req->stylesheet);
919             add_xsd_string(ptr, "database", req->database);
920         }
921         else if ((*p)->which == Z_SRW_scan_response)
922         {
923             Z_SRW_scanResponse *res = (*p)->u.scan_response;
924             xmlNodePtr ptr = xmlNewChild(pptr, 0, BAD_CAST "scanResponse", 0);
925             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
926             xmlSetNs(ptr, ns_srw);
927
928             add_xsd_string(ptr, "version", (*p)->srw_version);
929
930             if (res->num_terms)
931             {
932                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "terms", 0);
933                 yaz_srw_terms(o, rptr, &res->terms, &res->num_terms,
934                               client_data, ns);
935             }
936             if (res->num_diagnostics)
937             {
938                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "diagnostics",
939                                               0);
940                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
941                                     &res->num_diagnostics, client_data, ns);
942             }
943         }
944         else
945             return -1;
946
947     }
948     return 0;
949 }
950
951 int yaz_ucp_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
952                   void *client_data, const char *ns)
953 {
954     xmlNodePtr pptr = (xmlNodePtr) vptr;
955     if (o->direction == ODR_DECODE)
956     {
957         Z_SRW_PDU **p = handler_data;
958         xmlNodePtr method = pptr->children;
959
960         while (method && method->type == XML_TEXT_NODE)
961             method = method->next;
962         
963         if (!method)
964             return -1;
965         if (method->type != XML_ELEMENT_NODE)
966             return -1;
967
968         *p = (Z_SRW_PDU *) odr_malloc(o, sizeof(**p));
969         (*p)->srw_version = odr_strdup(o, "1.1");
970         
971         if (!xmlStrcmp(method->name, BAD_CAST "updateRequest"))
972         {
973             xmlNodePtr ptr = method->children;
974             Z_SRW_updateRequest *req;
975
976             (*p)->which = Z_SRW_update_request;
977             req = (*p)->u.update_request = (Z_SRW_updateRequest *)
978                 odr_malloc(o, sizeof(*req));
979             req->database = 0;
980             req->operation = 0;
981             req->recordId = 0;
982             req->recordVersion = 0;
983             req->recordOldVersion = 0;
984             req->record.recordData_buf = 0;
985             req->record.recordData_len = 0;
986             req->record.recordSchema = 0;
987             req->record.recordPacking = 0;
988             req->extra_record = 0;
989             req->extraRequestData = 0;
990             req->stylesheet = 0;
991
992             char *oper = 0;
993             
994             for (; ptr; ptr = ptr->next)
995             {
996                 if (match_xsd_string(ptr, "version", o,
997                                      &(*p)->srw_version))
998                     ;
999                 else if (match_xsd_string(ptr, "operation", o, 
1000                                           &oper)){
1001                     if ( oper ){
1002                         if ( !strcmp(oper, "delete"))
1003                             req->operation = "delete";
1004                         else if (!strcmp(oper,"replace" ))
1005                             req->operation = "replace";
1006                         else if ( !strcmp( oper, "insert"))
1007                             req->operation = "insert";
1008                     }
1009                 }
1010                 else if (match_xsd_string(ptr, "recordId", o,
1011                                           &req->recordId))
1012                     ;
1013                 else if (match_xsd_string(ptr, "recordVersion", o,
1014                                           &req->recordVersion))
1015                     ;
1016                 else if (match_element(ptr, "record"))
1017                     yaz_srw_record(o, ptr, &req->record, &req->extra_record,
1018                                    client_data, ns);
1019                 else if (match_xsd_string(ptr, "stylesheet", o,
1020                                            &req->stylesheet))
1021                     ;
1022                 else if (match_xsd_string(ptr, "database", o,
1023                                            &req->database))
1024                     ;
1025             }
1026         }
1027         else if (!xmlStrcmp(method->name, BAD_CAST "updateResponse"))
1028         {
1029             xmlNodePtr ptr = method->children;
1030             Z_SRW_updateResponse *res;
1031
1032             (*p)->which = Z_SRW_update_response;
1033             res = (*p)->u.update_response = (Z_SRW_updateResponse *)
1034                 odr_malloc(o, sizeof(*res));
1035
1036             res->operationStatus = 0;
1037             res->recordId = 0;
1038             res->recordVersion = 0;
1039             res->recordChecksum = 0;
1040             res->diagnostics = 0;
1041             res->num_diagnostics = 0;
1042             res->record.recordData_buf = 0;
1043             res->record.recordData_len = 0;
1044             res->record.recordSchema = 0;
1045             res->record.recordPacking = 0;
1046             res->extra_record = 0;
1047             res->extraResponseData = 0;
1048
1049             for (; ptr; ptr = ptr->next)
1050             {
1051                 if (match_xsd_string(ptr, "version", o,
1052                                      &(*p)->srw_version))
1053                     ;
1054                 else if (match_xsd_string(ptr, "operationStatus", o, 
1055                                       &res->operationStatus ))
1056                     ;
1057                 else if (match_xsd_string(ptr, "recordId", o, 
1058                                           &res->recordId))
1059                     ;
1060                 else if (match_xsd_string(ptr, "recordVersion", o, 
1061                                            &res->recordVersion ))
1062                     ;
1063                 else if (match_element(ptr, "record"))
1064                     yaz_srw_record(o, ptr, &res->record, &res->extra_record,
1065                                    client_data, ns);
1066                 else if (match_element(ptr, "diagnostics"))
1067                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
1068                                         &res->num_diagnostics,
1069                                         client_data, ns);
1070             }
1071         }
1072         else if (!xmlStrcmp(method->name, BAD_CAST "explainUpdateRequest"))
1073         {
1074         }
1075         else if (!xmlStrcmp(method->name, BAD_CAST "explainUpdateResponse"))
1076         {
1077         }
1078         else
1079         {
1080             *p = 0;
1081             return -1;
1082         }
1083     }
1084     else if (o->direction == ODR_ENCODE)
1085     {
1086         Z_SRW_PDU **p = handler_data;
1087         xmlNsPtr ns_srw;
1088
1089         if ((*p)->which == Z_SRW_update_request)
1090         {
1091             Z_SRW_updateRequest *req = (*p)->u.update_request;
1092             xmlNodePtr ptr = xmlNewChild(pptr, 0, "updateRequest", 0);
1093             ns_srw = xmlNewNs(ptr, ns, "zu");
1094             xmlSetNs(ptr, ns_srw);
1095
1096             add_xsd_string(ptr, "version", (*p)->srw_version);
1097             add_xsd_string(ptr, "stylesheet", req->stylesheet);
1098             add_xsd_string(ptr, "database", req->database);
1099         }
1100         else if ((*p)->which == Z_SRW_update_response)
1101         {
1102             Z_SRW_updateResponse *res = (*p)->u.update_response;
1103             xmlNodePtr ptr = xmlNewChild(pptr, 0, "updateResponse", 0);
1104             ns_srw = xmlNewNs(ptr, ns, "zu");
1105             xmlSetNs(ptr, ns_srw);
1106             
1107             add_xsd_string(ptr, "version", (*p)->srw_version);
1108             add_xsd_string(ptr, "operationStatus", res->operationStatus );
1109             add_xsd_string(ptr, "recordId", res->recordId );
1110             if (res->recordVersion)
1111                 add_xsd_string(ptr, "recordVersion", res->recordVersion );
1112             if (res->recordChecksum)
1113                 add_xsd_string(ptr, "recordChecksum", res->recordChecksum );
1114             if (res->record.recordData_len)
1115             {
1116                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "record", 0);
1117                 yaz_srw_record(o, rptr, &res->record, &res->extra_record,
1118                                client_data, ns);
1119             }
1120             if (res->num_diagnostics)
1121             {
1122                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
1123                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
1124                                     &res->num_diagnostics, client_data, ns);
1125             }
1126             if ( res->extraResponseData )
1127                 add_xsd_string(ptr, "extraResponseData", res->extraResponseData);
1128         }
1129         else
1130             return -1;
1131
1132     }
1133     return 0;
1134 }
1135
1136 #endif
1137
1138
1139 /*
1140  * Local variables:
1141  * c-basic-offset: 4
1142  * indent-tabs-mode: nil
1143  * End:
1144  * vim: shiftwidth=4 tabstop=8 expandtab
1145  */
1146