138f8a6389b869e94b938516b01a1f5d730dd042
[yaz-moved-to-github.git] / src / srw.c
1 /*
2  * Copyright (C) 1995-2006, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: srw.c,v 1.47 2006-08-16 22:47:10 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 YAZ_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 = 0;
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             {
263                 /* save position of Data until after the loop
264                    then we will know the packing (hopefully), and
265                    unpacking is done once
266                 */
267                 data_ptr = ptr;
268             }
269             else if (match_element(ptr, "extraRecordData"))
270             {
271                 *extra = (Z_SRW_extra_record *)
272                     odr_malloc(o, sizeof(Z_SRW_extra_record));
273                 yaz_srw_extra_record(o, ptr, *extra, client_data, ns);
274             }
275         }
276         if (data_ptr)
277         {
278             switch(pack)
279             {
280             case Z_SRW_recordPacking_XML:
281                 match_xsd_XML_n(data_ptr, "recordData", o, 
282                                 &rec->recordData_buf, &rec->recordData_len);
283                 break;
284             case Z_SRW_recordPacking_URL:
285                 /* just store it as a string.
286                    leave it to the backend to collect the document */
287                 match_xsd_string_n(data_ptr, "recordData", o, 
288                                    &rec->recordData_buf, &rec->recordData_len);
289                 break;
290             case Z_SRW_recordPacking_string:
291                 match_xsd_string_n(data_ptr, "recordData", o, 
292                                    &rec->recordData_buf, &rec->recordData_len);
293                 break;
294             }
295         }
296         rec->recordPacking = pack;
297     }
298     else if (o->direction == ODR_ENCODE)
299     {
300         xmlNodePtr ptr = pptr;
301         int pack = rec->recordPacking;
302         add_xsd_string(ptr, "recordSchema", rec->recordSchema);
303
304         switch(pack)
305         {
306         case Z_SRW_recordPacking_string:
307             add_xsd_string(ptr, "recordPacking", "string");
308             add_xsd_string_n(ptr, "recordData", rec->recordData_buf,
309                              rec->recordData_len);
310             break;
311         case Z_SRW_recordPacking_XML:
312             add_xsd_string(ptr, "recordPacking", "xml");
313             add_XML_n(ptr, "recordData", rec->recordData_buf,
314                       rec->recordData_len);
315             break;
316         case Z_SRW_recordPacking_URL:
317             add_xsd_string(ptr, "recordPacking", "url");
318             add_xsd_string_n(ptr, "recordData", rec->recordData_buf,
319                              rec->recordData_len);
320             break;
321         }
322         if (rec->recordPosition)
323             add_xsd_integer(ptr, "recordPosition", rec->recordPosition );
324         if (extra && *extra)
325         {
326             xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "extraRecordData",
327                                           0);
328             yaz_srw_extra_record(o, rptr, *extra, client_data, ns);
329         }
330     }
331     return 0;
332 }
333
334 static int yaz_srw_records(ODR o, xmlNodePtr pptr, Z_SRW_record **recs,
335                            Z_SRW_extra_record ***extra,
336                            int *num, void *client_data, const char *ns)
337 {
338     if (o->direction == ODR_DECODE)
339     {
340         int i;
341         xmlNodePtr ptr;
342         *num = 0;
343         for (ptr = pptr->children; ptr; ptr = ptr->next)
344         {
345             if (ptr->type == XML_ELEMENT_NODE &&
346                 !xmlStrcmp(ptr->name, BAD_CAST "record"))
347                 (*num)++;
348         }
349         if (!*num)
350             return 1;
351         *recs = (Z_SRW_record *) odr_malloc(o, *num * sizeof(**recs));
352         *extra = (Z_SRW_extra_record **) odr_malloc(o, *num * sizeof(**extra));
353         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next)
354         {
355             if (ptr->type == XML_ELEMENT_NODE &&
356                 !xmlStrcmp(ptr->name, BAD_CAST "record"))
357             {
358                 yaz_srw_record(o, ptr, *recs + i, *extra + i, client_data, ns);
359                 i++;
360             }
361         }
362     }
363     else if (o->direction == ODR_ENCODE)
364     {
365         int i;
366         for (i = 0; i < *num; i++)
367         {
368             xmlNodePtr rptr = xmlNewChild(pptr, 0, BAD_CAST "record",
369                                           0);
370             yaz_srw_record(o, rptr, (*recs)+i, (*extra ? *extra + i : 0),
371                            client_data, ns);
372         }
373     }
374     return 0;
375 }
376
377 static int yaz_srw_diagnostics(ODR o, xmlNodePtr pptr, Z_SRW_diagnostic **recs,
378                                int *num, void *client_data, const char *ns)
379 {
380     if (o->direction == ODR_DECODE)
381     {
382         int i;
383         xmlNodePtr ptr;
384         *num = 0;
385         for (ptr = pptr->children; ptr; ptr = ptr->next)
386         {
387             if (ptr->type == XML_ELEMENT_NODE &&
388                 !xmlStrcmp(ptr->name, BAD_CAST "diagnostic"))
389                 (*num)++;
390         }
391         if (!*num)
392             return 1;
393         *recs = (Z_SRW_diagnostic *) odr_malloc(o, *num * sizeof(**recs));
394         for (i = 0; i < *num; i++)
395         {
396             (*recs)[i].uri = 0;
397             (*recs)[i].details = 0;
398             (*recs)[i].message = 0;
399         } 
400         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next)
401         {
402             if (ptr->type == XML_ELEMENT_NODE &&
403                 !xmlStrcmp(ptr->name, BAD_CAST "diagnostic"))
404             {
405                 xmlNodePtr rptr;
406                 (*recs)[i].uri = 0;
407                 (*recs)[i].details = 0;
408                 (*recs)[i].message = 0;
409                 for (rptr = ptr->children; rptr; rptr = rptr->next)
410                 {
411                     if (match_xsd_string(rptr, "uri", o, 
412                                          &(*recs)[i].uri))
413                         ;
414                     else if (match_xsd_string(rptr, "details", o, 
415                                               &(*recs)[i].details))
416                         ;
417                     else if (match_xsd_string(rptr, "message", o, 
418                                               &(*recs)[i].message))
419                         ;
420                 }
421                 i++;
422             }
423         }
424     }
425     else if (o->direction == ODR_ENCODE)
426     {
427         int i;
428         xmlNsPtr ns_diag =
429             xmlNewNs(pptr, BAD_CAST
430                      "http://www.loc.gov/zing/srw/diagnostic/", 0);
431         for (i = 0; i < *num; i++)
432         {
433             const char *std_diag = "info:srw/diagnostic/1/";
434             xmlNodePtr rptr = xmlNewChild(pptr, ns_diag,
435                                           BAD_CAST "diagnostic", 0);
436             add_xsd_string(rptr, "uri", (*recs)[i].uri);
437             if ((*recs)[i].message)
438                 add_xsd_string(rptr, "message", (*recs)[i].message);
439             else if ((*recs)[i].uri && 
440                      !strncmp((*recs)[i].uri, std_diag, strlen(std_diag)))
441             {
442                 int no = atoi((*recs)[i].uri + strlen(std_diag));
443                 const char *message = yaz_diag_srw_str(no);
444                 if (message)
445                     add_xsd_string(rptr, "message", message);
446             }
447             add_xsd_string(rptr, "details", (*recs)[i].details);
448         }
449     }
450     return 0;
451 }
452
453 static int yaz_srw_term(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm *term,
454                         void *client_data, const char *ns)
455 {
456     if (o->direction == ODR_DECODE)
457     {
458         xmlNodePtr ptr;
459         term->value = 0;
460         term->numberOfRecords = 0;
461         term->displayTerm = 0;
462         term->whereInList = 0;
463         for (ptr = pptr->children; ptr; ptr = ptr->next)
464         {
465             if (match_xsd_string(ptr, "value", o,  &term->value))
466                 ;
467             else if (match_xsd_integer(ptr, "numberOfRecords", o, 
468                                    &term->numberOfRecords))
469                 ;
470             else if (match_xsd_string(ptr, "displayTerm", o, 
471                                       &term->displayTerm))
472                 ;
473             else if (match_xsd_string(ptr, "whereInList", o, 
474                                       &term->whereInList))
475                 ;
476         }
477     }
478     else if (o->direction == ODR_ENCODE)
479     {
480         xmlNodePtr ptr = pptr;
481         add_xsd_string(ptr, "value", term->value);
482         add_xsd_integer(ptr, "numberOfRecords", term->numberOfRecords);
483         add_xsd_string(ptr, "displayTerm", term->displayTerm);
484         add_xsd_string(ptr, "whereInList", term->whereInList);
485     }
486     return 0;
487 }
488
489 static int yaz_srw_terms(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm **terms,
490                          int *num, void *client_data, const char *ns)
491 {
492     if (o->direction == ODR_DECODE)
493     {
494         int i;
495         xmlNodePtr ptr;
496         *num = 0;
497         for (ptr = pptr->children; ptr; ptr = ptr->next)
498         {
499             if (ptr->type == XML_ELEMENT_NODE &&
500                 !xmlStrcmp(ptr->name, BAD_CAST "term"))
501                 (*num)++;
502         }
503         if (!*num)
504             return 1;
505         *terms = (Z_SRW_scanTerm *) odr_malloc(o, *num * sizeof(**terms));
506         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
507         {
508             if (ptr->type == XML_ELEMENT_NODE &&
509                 !xmlStrcmp(ptr->name, BAD_CAST "term"))
510                 yaz_srw_term(o, ptr, (*terms)+i, client_data, ns);
511         }
512     }
513     else if (o->direction == ODR_ENCODE)
514     {
515         int i;
516         for (i = 0; i < *num; i++)
517         {
518             xmlNodePtr rptr = xmlNewChild(pptr, 0, BAD_CAST "term", 0);
519             yaz_srw_term(o, rptr, (*terms)+i, client_data, ns);
520         }
521     }
522     return 0;
523 }
524
525 Z_SRW_PDU *yaz_srw_get_core_v_1_1(ODR o)
526 {
527     Z_SRW_PDU *p = (Z_SRW_PDU *) odr_malloc(o, sizeof(*p));
528     p->srw_version = odr_strdup(o, "1.1");
529     p->username = 0;
530     p->password = 0;
531     p->extra_args = 0;
532     return p;
533 }
534
535 int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
536                   void *client_data, const char *ns)
537 {
538     xmlNodePtr pptr = (xmlNodePtr) vptr;
539     if (o->direction == ODR_DECODE)
540     {
541         Z_SRW_PDU **p = handler_data;
542         xmlNodePtr method = pptr->children;
543
544         while (method && method->type == XML_TEXT_NODE)
545             method = method->next;
546         
547         if (!method)
548             return -1;
549         if (method->type != XML_ELEMENT_NODE)
550             return -1;
551
552         *p = yaz_srw_get_core_v_1_1(o);
553         
554         if (!xmlStrcmp(method->name, BAD_CAST "searchRetrieveRequest"))
555         {
556             xmlNodePtr ptr = method->children;
557             Z_SRW_searchRetrieveRequest *req;
558
559             (*p)->which = Z_SRW_searchRetrieve_request;
560             req = (*p)->u.request = (Z_SRW_searchRetrieveRequest *)
561                 odr_malloc(o, sizeof(*req));
562             req->query_type = Z_SRW_query_type_cql;
563             req->query.cql = 0;
564             req->sort_type = Z_SRW_sort_type_none;
565             req->sort.none = 0;
566             req->startRecord = 0;
567             req->maximumRecords = 0;
568             req->recordSchema = 0;
569             req->recordPacking = 0;
570             req->recordXPath = 0;
571             req->resultSetTTL = 0;
572             req->stylesheet = 0;
573             req->database = 0;
574
575             for (; ptr; ptr = ptr->next)
576             {
577                 if (match_xsd_string(ptr, "version", o,
578                                      &(*p)->srw_version))
579                     ;
580                 else if (match_xsd_string(ptr, "query", o, 
581                                      &req->query.cql))
582                     req->query_type = Z_SRW_query_type_cql;
583                 else if (match_xsd_string(ptr, "pQuery", o, 
584                                      &req->query.pqf))
585                     req->query_type = Z_SRW_query_type_pqf;
586                 else if (match_xsd_string(ptr, "xQuery", o, 
587                                      &req->query.xcql))
588                     req->query_type = Z_SRW_query_type_xcql;
589                 else if (match_xsd_integer(ptr, "startRecord", o,
590                                            &req->startRecord))
591                     ;
592                 else if (match_xsd_integer(ptr, "maximumRecords", o,
593                                            &req->maximumRecords))
594                     ;
595                 else if (match_xsd_string(ptr, "recordPacking", o,
596                                           &req->recordPacking))
597                     ;
598                 else if (match_xsd_string(ptr, "recordSchema", o, 
599                                           &req->recordSchema))
600                     ;
601                 else if (match_xsd_string(ptr, "recordXPath", o,
602                                           &req->recordXPath))
603                     ;
604                 else if (match_xsd_integer(ptr, "resultSetTTL", o,
605                                            &req->resultSetTTL))
606                     ;
607                 else if (match_xsd_string(ptr, "sortKeys", o, 
608                                           &req->sort.sortKeys))
609                     req->sort_type = Z_SRW_sort_type_sort;
610                 else if (match_xsd_string(ptr, "stylesheet", o,
611                                            &req->stylesheet))
612                     ;
613                 else if (match_xsd_string(ptr, "database", o,
614                                            &req->database))
615                     ;
616             }
617         }
618         else if (!xmlStrcmp(method->name, BAD_CAST "searchRetrieveResponse"))
619         {
620             xmlNodePtr ptr = method->children;
621             Z_SRW_searchRetrieveResponse *res;
622
623             (*p)->which = Z_SRW_searchRetrieve_response;
624             res = (*p)->u.response = (Z_SRW_searchRetrieveResponse *)
625                 odr_malloc(o, sizeof(*res));
626
627             res->numberOfRecords = 0;
628             res->resultSetId = 0;
629             res->resultSetIdleTime = 0;
630             res->records = 0;
631             res->num_records = 0;
632             res->diagnostics = 0;
633             res->num_diagnostics = 0;
634             res->nextRecordPosition = 0;
635
636             for (; ptr; ptr = ptr->next)
637             {
638                 if (match_xsd_string(ptr, "version", o,
639                                      &(*p)->srw_version))
640                     ;
641                 else if (match_xsd_integer(ptr, "numberOfRecords", o, 
642                                       &res->numberOfRecords))
643                     ;
644                 else if (match_xsd_string(ptr, "resultSetId", o, 
645                                           &res->resultSetId))
646                     ;
647                 else if (match_xsd_integer(ptr, "resultSetIdleTime", o, 
648                                            &res->resultSetIdleTime))
649                     ;
650                 else if (match_element(ptr, "records"))
651                     yaz_srw_records(o, ptr, &res->records,
652                                     &res->extra_records, 
653                                     &res->num_records, client_data, ns);
654                 else if (match_xsd_integer(ptr, "nextRecordPosition", o,
655                                            &res->nextRecordPosition))
656                     ;
657                 else if (match_element(ptr, "diagnostics"))
658                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
659                                         &res->num_diagnostics,
660                                         client_data, ns);
661             }
662         }
663         else if (!xmlStrcmp(method->name, BAD_CAST "explainRequest"))
664         {
665             Z_SRW_explainRequest *req;
666             xmlNodePtr ptr = method->children;
667             
668             (*p)->which = Z_SRW_explain_request;
669             req = (*p)->u.explain_request = (Z_SRW_explainRequest *)
670                 odr_malloc(o, sizeof(*req));
671             req->recordPacking = 0;
672             req->database = 0;
673             req->stylesheet = 0;
674             for (; ptr; ptr = ptr->next)
675             {
676                 if (match_xsd_string(ptr, "version", o,
677                                            &(*p)->srw_version))
678                     ;
679                 else if (match_xsd_string(ptr, "stylesheet", o,
680                                           &req->stylesheet))
681                     ;
682                 else if (match_xsd_string(ptr, "recordPacking", o,
683                                      &req->recordPacking))
684                     ;
685                 else if (match_xsd_string(ptr, "database", o,
686                                      &req->database))
687                     ;
688             }
689         }
690         else if (!xmlStrcmp(method->name, BAD_CAST "explainResponse"))
691         {
692             Z_SRW_explainResponse *res;
693             xmlNodePtr ptr = method->children;
694
695             (*p)->which = Z_SRW_explain_response;
696             res = (*p)->u.explain_response = (Z_SRW_explainResponse*)
697                 odr_malloc(o, sizeof(*res));
698             res->diagnostics = 0;
699             res->num_diagnostics = 0;
700             res->record.recordSchema = 0;
701             res->record.recordData_buf = 0;
702             res->record.recordData_len = 0;
703             res->record.recordPosition = 0;
704
705             for (; ptr; ptr = ptr->next)
706             {
707                 if (match_xsd_string(ptr, "version", o,
708                                            &(*p)->srw_version))
709                     ;
710                 else if (match_element(ptr, "record"))
711                     yaz_srw_record(o, ptr, &res->record, &res->extra_record,
712                                    client_data, ns);
713                 else if (match_element(ptr, "diagnostics"))
714                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
715                                         &res->num_diagnostics,
716                                         client_data, ns);
717                 ;
718             }
719         }
720         else if (!xmlStrcmp(method->name, BAD_CAST "scanRequest"))
721         {
722             Z_SRW_scanRequest *req;
723             xmlNodePtr ptr = method->children;
724
725             (*p)->which = Z_SRW_scan_request;
726             req = (*p)->u.scan_request = (Z_SRW_scanRequest *)
727                 odr_malloc(o, sizeof(*req));
728             req->query_type = Z_SRW_query_type_cql;
729             req->scanClause.cql = 0;
730             req->responsePosition = 0;
731             req->maximumTerms = 0;
732             req->stylesheet = 0;
733             req->database = 0;
734             
735             for (; ptr; ptr = ptr->next)
736             {
737                 if (match_xsd_string(ptr, "version", o,
738                                      &(*p)->srw_version))
739                     ;
740                 else if (match_xsd_string(ptr, "scanClause", o,
741                                      &req->scanClause.cql))
742                     ;
743                 else if (match_xsd_string(ptr, "pScanClause", o,
744                                           &req->scanClause.pqf))
745                 {
746                     req->query_type = Z_SRW_query_type_pqf;
747                 }
748                 else if (match_xsd_integer(ptr, "responsePosition", o,
749                                            &req->responsePosition))
750                     ;
751                 else if (match_xsd_integer(ptr, "maximumTerms", o,
752                                            &req->maximumTerms))
753                     ;
754                 else if (match_xsd_string(ptr, "stylesheet", o,
755                                           &req->stylesheet))
756                     ;
757                 else if (match_xsd_string(ptr, "database", o,
758                                           &req->database))
759                     ;
760             }
761         }
762         else if (!xmlStrcmp(method->name, BAD_CAST "scanResponse"))
763         {
764             Z_SRW_scanResponse *res;
765             xmlNodePtr ptr = method->children;
766
767             (*p)->which = Z_SRW_scan_response;
768             res = (*p)->u.scan_response = (Z_SRW_scanResponse *)
769                 odr_malloc(o, sizeof(*res));
770             res->terms = 0;
771             res->num_terms = 0;
772             res->diagnostics = 0;
773             res->num_diagnostics = 0;
774             
775             for (; ptr; ptr = ptr->next)
776             {
777                 if (match_xsd_string(ptr, "version", o,
778                                      &(*p)->srw_version))
779                     ;
780                 else if (match_element(ptr, "terms"))
781                     yaz_srw_terms(o, ptr, &res->terms,
782                                   &res->num_terms, client_data,
783                                   ns);
784                 else if (match_element(ptr, "diagnostics"))
785                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
786                                         &res->num_diagnostics,
787                                         client_data, ns);
788             }
789         }
790         else
791         {
792             *p = 0;
793             return -1;
794         }
795     }
796     else if (o->direction == ODR_ENCODE)
797     {
798         Z_SRW_PDU **p = handler_data;
799         xmlNsPtr ns_srw;
800         
801         if ((*p)->which == Z_SRW_searchRetrieve_request)
802         {
803             Z_SRW_searchRetrieveRequest *req = (*p)->u.request;
804             xmlNodePtr ptr = xmlNewChild(pptr, 0,
805                                          BAD_CAST "searchRetrieveRequest", 0);
806             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
807             xmlSetNs(ptr, ns_srw);
808
809             if ((*p)->srw_version)
810                 add_xsd_string(ptr, "version", (*p)->srw_version);
811             switch(req->query_type)
812             {
813             case Z_SRW_query_type_cql:
814                 add_xsd_string(ptr, "query", req->query.cql);
815                 break;
816             case Z_SRW_query_type_xcql:
817                 add_xsd_string(ptr, "xQuery", req->query.xcql);
818                 break;
819             case Z_SRW_query_type_pqf:
820                 add_xsd_string(ptr, "pQuery", req->query.pqf);
821                 break;
822             }
823             add_xsd_integer(ptr, "startRecord", req->startRecord);
824             add_xsd_integer(ptr, "maximumRecords", req->maximumRecords);
825             add_xsd_string(ptr, "recordPacking", req->recordPacking);
826             add_xsd_string(ptr, "recordSchema", req->recordSchema);
827             add_xsd_string(ptr, "recordXPath", req->recordXPath);
828             add_xsd_integer(ptr, "resultSetTTL", req->resultSetTTL);
829             switch(req->sort_type)
830             {
831             case Z_SRW_sort_type_none:
832                 break;
833             case Z_SRW_sort_type_sort:
834                 add_xsd_string(ptr, "sortKeys", req->sort.sortKeys);
835                 break;
836             case Z_SRW_sort_type_xSort:
837                 add_xsd_string(ptr, "xSortKeys", req->sort.xSortKeys);
838                 break;
839             }
840             add_xsd_string(ptr, "stylesheet", req->stylesheet);
841             add_xsd_string(ptr, "database", req->database);
842         }
843         else if ((*p)->which == Z_SRW_searchRetrieve_response)
844         {
845             Z_SRW_searchRetrieveResponse *res = (*p)->u.response;
846             xmlNodePtr ptr = xmlNewChild(pptr, 0,
847                                          BAD_CAST "searchRetrieveResponse", 0);
848             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
849             xmlSetNs(ptr, ns_srw);
850
851             if ((*p)->srw_version)
852                 add_xsd_string(ptr, "version", (*p)->srw_version);
853             add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
854             add_xsd_string(ptr, "resultSetId", res->resultSetId);
855             add_xsd_integer(ptr, "resultSetIdleTime", res->resultSetIdleTime);
856             if (res->num_records)
857             {
858                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "records", 0);
859                 yaz_srw_records(o, rptr, &res->records, &res->extra_records,
860                                 &res->num_records,
861                                 client_data, ns);
862             }
863             add_xsd_integer(ptr, "nextRecordPosition",
864                             res->nextRecordPosition);
865             if (res->num_diagnostics)
866             {
867                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "diagnostics",
868                                               0);
869                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
870                                     &res->num_diagnostics, client_data, ns);
871             }
872         }
873         else if ((*p)->which == Z_SRW_explain_request)
874         {
875             Z_SRW_explainRequest *req = (*p)->u.explain_request;
876             xmlNodePtr ptr = xmlNewChild(pptr, 0, BAD_CAST "explainRequest",
877                                          0);
878             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
879             xmlSetNs(ptr, ns_srw);
880
881             add_xsd_string(ptr, "version", (*p)->srw_version);
882             add_xsd_string(ptr, "recordPacking", req->recordPacking);
883             add_xsd_string(ptr, "stylesheet", req->stylesheet);
884             add_xsd_string(ptr, "database", req->database);
885         }
886         else if ((*p)->which == Z_SRW_explain_response)
887         {
888             Z_SRW_explainResponse *res = (*p)->u.explain_response;
889             xmlNodePtr ptr = xmlNewChild(pptr, 0, BAD_CAST "explainResponse",
890                                          0);
891             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
892             xmlSetNs(ptr, ns_srw);
893
894             add_xsd_string(ptr, "version", (*p)->srw_version);
895             if (1)
896             {
897                 xmlNodePtr ptr1 = xmlNewChild(ptr, 0, BAD_CAST "record", 0);
898                 yaz_srw_record(o, ptr1, &res->record, &res->extra_record,
899                                client_data, ns);
900             }
901             if (res->num_diagnostics)
902             {
903                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "diagnostics",
904                                               0);
905                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
906                                     &res->num_diagnostics, client_data, ns);
907             }
908         }
909         else if ((*p)->which == Z_SRW_scan_request)
910         {
911             Z_SRW_scanRequest *req = (*p)->u.scan_request;
912             xmlNodePtr ptr = xmlNewChild(pptr, 0, BAD_CAST "scanRequest", 0);
913             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
914             xmlSetNs(ptr, ns_srw);
915
916             add_xsd_string(ptr, "version", (*p)->srw_version);
917             switch(req->query_type)
918             {
919             case Z_SRW_query_type_cql:
920                 add_xsd_string(ptr, "scanClause", req->scanClause.cql);
921                 break;
922             case Z_SRW_query_type_pqf:
923                 add_xsd_string(ptr, "pScanClause", req->scanClause.pqf);
924                 break;
925             }
926             add_xsd_integer(ptr, "responsePosition", req->responsePosition);
927             add_xsd_integer(ptr, "maximumTerms", req->maximumTerms);
928             add_xsd_string(ptr, "stylesheet", req->stylesheet);
929             add_xsd_string(ptr, "database", req->database);
930         }
931         else if ((*p)->which == Z_SRW_scan_response)
932         {
933             Z_SRW_scanResponse *res = (*p)->u.scan_response;
934             xmlNodePtr ptr = xmlNewChild(pptr, 0, BAD_CAST "scanResponse", 0);
935             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
936             xmlSetNs(ptr, ns_srw);
937
938             add_xsd_string(ptr, "version", (*p)->srw_version);
939
940             if (res->num_terms)
941             {
942                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "terms", 0);
943                 yaz_srw_terms(o, rptr, &res->terms, &res->num_terms,
944                               client_data, ns);
945             }
946             if (res->num_diagnostics)
947             {
948                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "diagnostics",
949                                               0);
950                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
951                                     &res->num_diagnostics, client_data, ns);
952             }
953         }
954         else
955             return -1;
956
957     }
958     return 0;
959 }
960
961 int yaz_ucp_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
962                   void *client_data, const char *ns)
963 {
964     xmlNodePtr pptr = (xmlNodePtr) vptr;
965     if (o->direction == ODR_DECODE)
966     {
967         Z_SRW_PDU **p = handler_data;
968         xmlNodePtr method = pptr->children;
969
970         while (method && method->type == XML_TEXT_NODE)
971             method = method->next;
972         
973         if (!method)
974             return -1;
975         if (method->type != XML_ELEMENT_NODE)
976             return -1;
977
978         *p = yaz_srw_get_core_v_1_1(o);
979         
980         if (!xmlStrcmp(method->name, BAD_CAST "updateRequest"))
981         {
982             xmlNodePtr ptr = method->children;
983             Z_SRW_updateRequest *req;
984             char *oper = 0;
985
986             (*p)->which = Z_SRW_update_request;
987             req = (*p)->u.update_request = (Z_SRW_updateRequest *)
988                 odr_malloc(o, sizeof(*req));
989             req->database = 0;
990             req->operation = 0;
991             req->recordId = 0;
992             req->recordVersion = 0;
993             req->recordOldVersion = 0;
994             req->record.recordData_buf = 0;
995             req->record.recordData_len = 0;
996             req->record.recordSchema = 0;
997             req->record.recordPacking = 0;
998             req->extra_record = 0;
999             req->extraRequestData = 0;
1000             req->stylesheet = 0;
1001
1002             for (; ptr; ptr = ptr->next)
1003             {
1004                 if (match_xsd_string(ptr, "version", o,
1005                                      &(*p)->srw_version))
1006                     ;
1007                 else if (match_xsd_string(ptr, "operation", o, 
1008                                           &oper)){
1009                     if ( oper ){
1010                         if ( !strcmp(oper, "delete"))
1011                             req->operation = "delete";
1012                         else if (!strcmp(oper,"replace" ))
1013                             req->operation = "replace";
1014                         else if ( !strcmp( oper, "insert"))
1015                             req->operation = "insert";
1016                     }
1017                 }
1018                 else if (match_xsd_string(ptr, "recordId", o,
1019                                           &req->recordId))
1020                     ;
1021                 else if (match_xsd_string(ptr, "recordVersion", o,
1022                                           &req->recordVersion))
1023                     ;
1024                 else if (match_element(ptr, "record"))
1025                     yaz_srw_record(o, ptr, &req->record, &req->extra_record,
1026                                    client_data, ns);
1027                 else if (match_xsd_string(ptr, "stylesheet", o,
1028                                            &req->stylesheet))
1029                     ;
1030                 else if (match_xsd_string(ptr, "database", o,
1031                                            &req->database))
1032                     ;
1033             }
1034         }
1035         else if (!xmlStrcmp(method->name, BAD_CAST "updateResponse"))
1036         {
1037             xmlNodePtr ptr = method->children;
1038             Z_SRW_updateResponse *res;
1039
1040             (*p)->which = Z_SRW_update_response;
1041             res = (*p)->u.update_response = (Z_SRW_updateResponse *)
1042                 odr_malloc(o, sizeof(*res));
1043
1044             res->operationStatus = 0;
1045             res->recordId = 0;
1046             res->recordVersion = 0;
1047             res->recordChecksum = 0;
1048             res->diagnostics = 0;
1049             res->num_diagnostics = 0;
1050             res->record.recordData_buf = 0;
1051             res->record.recordData_len = 0;
1052             res->record.recordSchema = 0;
1053             res->record.recordPacking = 0;
1054             res->extra_record = 0;
1055             res->extraResponseData = 0;
1056
1057             for (; ptr; ptr = ptr->next)
1058             {
1059                 if (match_xsd_string(ptr, "version", o,
1060                                      &(*p)->srw_version))
1061                     ;
1062                 else if (match_xsd_string(ptr, "operationStatus", o, 
1063                                       &res->operationStatus ))
1064                     ;
1065                 else if (match_xsd_string(ptr, "recordId", o, 
1066                                           &res->recordId))
1067                     ;
1068                 else if (match_xsd_string(ptr, "recordVersion", o, 
1069                                            &res->recordVersion ))
1070                     ;
1071                 else if (match_element(ptr, "record"))
1072                     yaz_srw_record(o, ptr, &res->record, &res->extra_record,
1073                                    client_data, ns);
1074                 else if (match_element(ptr, "diagnostics"))
1075                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
1076                                         &res->num_diagnostics,
1077                                         client_data, ns);
1078             }
1079         }
1080         else if (!xmlStrcmp(method->name, BAD_CAST "explainUpdateRequest"))
1081         {
1082         }
1083         else if (!xmlStrcmp(method->name, BAD_CAST "explainUpdateResponse"))
1084         {
1085         }
1086         else
1087         {
1088             *p = 0;
1089             return -1;
1090         }
1091     }
1092     else if (o->direction == ODR_ENCODE)
1093     {
1094         Z_SRW_PDU **p = handler_data;
1095         xmlNsPtr ns_srw;
1096
1097         if ((*p)->which == Z_SRW_update_request)
1098         {
1099             Z_SRW_updateRequest *req = (*p)->u.update_request;
1100             xmlNodePtr ptr = xmlNewChild(pptr, 0, BAD_CAST "updateRequest", 0);
1101             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zu");
1102             xmlSetNs(ptr, ns_srw);
1103
1104             add_xsd_string(ptr, "version", (*p)->srw_version);
1105             add_xsd_string(ptr, "stylesheet", req->stylesheet);
1106             add_xsd_string(ptr, "database", req->database);
1107         }
1108         else if ((*p)->which == Z_SRW_update_response)
1109         {
1110             Z_SRW_updateResponse *res = (*p)->u.update_response;
1111             xmlNodePtr ptr = xmlNewChild(pptr, 0, (xmlChar *) 
1112                                          "updateResponse", 0);
1113             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zu");
1114             xmlSetNs(ptr, ns_srw);
1115             
1116             add_xsd_string(ptr, "version", (*p)->srw_version);
1117             add_xsd_string(ptr, "operationStatus", res->operationStatus );
1118             add_xsd_string(ptr, "recordId", res->recordId );
1119             if (res->recordVersion)
1120                 add_xsd_string(ptr, "recordVersion", res->recordVersion );
1121             if (res->recordChecksum)
1122                 add_xsd_string(ptr, "recordChecksum", res->recordChecksum );
1123             if (res->record.recordData_len)
1124             {
1125                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "record", 0);
1126                 yaz_srw_record(o, rptr, &res->record, &res->extra_record,
1127                                client_data, ns);
1128             }
1129             if (res->num_diagnostics)
1130             {
1131                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "diagnostics", 0);
1132                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
1133                                     &res->num_diagnostics, client_data, ns);
1134             }
1135             if ( res->extraResponseData )
1136                 add_xsd_string(ptr, "extraResponseData", res->extraResponseData);
1137         }
1138         else
1139             return -1;
1140
1141     }
1142     return 0;
1143 }
1144
1145 #endif
1146
1147
1148 /*
1149  * Local variables:
1150  * c-basic-offset: 4
1151  * indent-tabs-mode: nil
1152  * End:
1153  * vim: shiftwidth=4 tabstop=8 expandtab
1154  */
1155