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