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