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