2 * Copyright (C) 1995-2005, Index Data ApS
3 * See the file LICENSE for details.
5 * $Id: srw.c,v 1.34 2005-02-04 20:27:19 adam Exp $
9 * \brief Implements SRW/SRU package encoding and decoding
15 #include <libxml/parser.h>
16 #include <libxml/tree.h>
18 static void add_XML_n(xmlNodePtr ptr, const char *elem, char *val, int len)
22 xmlDocPtr doc = xmlParseMemory(val,len);
25 xmlNodePtr c = xmlNewChild(ptr, 0, elem, 0);
26 xmlNodePtr t = xmlDocGetRootElement(doc);
27 xmlAddChild(c, xmlCopyNode(t,1));
33 xmlNodePtr add_xsd_string_n(xmlNodePtr ptr, const char *elem, const char *val,
38 xmlNodePtr c = xmlNewChild(ptr, 0, elem, 0);
39 xmlNodePtr t = xmlNewTextLen(val, len);
46 xmlNodePtr add_xsd_string(xmlNodePtr ptr, const char *elem, const char *val)
49 return xmlNewTextChild(ptr, 0, elem, val);
53 static void add_xsd_integer(xmlNodePtr ptr, const char *elem, const int *val)
58 sprintf(str, "%d", *val);
59 xmlNewTextChild(ptr, 0, elem, str);
63 static int match_element(xmlNodePtr ptr, const char *elem)
65 if (ptr->type == XML_ELEMENT_NODE && !strcmp(ptr->name, elem))
72 static int match_xsd_string_n(xmlNodePtr ptr, const char *elem, ODR o,
76 struct _xmlAttr *attr;
78 if (!match_element(ptr, elem))
81 for (attr = ptr->properties; attr; attr = attr->next)
82 if (!strcmp(attr->name, "type") &&
83 attr->children && attr->children->type == XML_TEXT_NODE)
85 const char *t = strchr(attr->children->content, ':');
89 t = attr->children->content;
90 if (!strcmp(t, "string"))
97 if (!ptr || ptr->type != XML_TEXT_NODE)
102 *val = odr_strdup(o, ptr->content);
104 *len = strlen(ptr->content);
109 static int match_xsd_string(xmlNodePtr ptr, const char *elem, ODR o,
112 return match_xsd_string_n(ptr, elem, o, val, 0);
115 static int match_xsd_XML_n(xmlNodePtr ptr, const char *elem, ODR o,
116 char **val, int *len)
120 if (!match_element(ptr, elem))
123 while (ptr && (ptr->type == XML_TEXT_NODE || ptr->type == XML_COMMENT_NODE))
127 buf = xmlBufferCreate();
129 xmlNodeDump(buf, ptr->doc, ptr, 0, 0);
131 *val = odr_malloc(o, buf->use+1);
132 memcpy (*val, buf->content, buf->use);
133 (*val)[buf->use] = '\0';
143 static int match_xsd_integer(xmlNodePtr ptr, const char *elem, ODR o, int **val)
146 struct _xmlAttr *attr;
148 if (!match_element(ptr, elem))
151 for (attr = ptr->properties; attr; attr = attr->next)
152 if (!strcmp(attr->name, "type") &&
153 attr->children && attr->children->type == XML_TEXT_NODE)
155 const char *t = strchr(attr->children->content, ':');
159 t = attr->children->content;
160 if (!strcmp(t, "integer"))
167 if (!ptr || ptr->type != XML_TEXT_NODE)
169 *val = odr_intdup(o, atoi(ptr->content));
173 static int yaz_srw_record(ODR o, xmlNodePtr pptr, Z_SRW_record *rec,
174 void *client_data, const char *ns)
176 if (o->direction == ODR_DECODE)
178 int pack = Z_SRW_recordPacking_string;
180 rec->recordSchema = 0;
181 rec->recordData_buf = 0;
182 rec->recordData_len = 0;
183 rec->recordPosition = 0;
184 for (ptr = pptr->children; ptr; ptr = ptr->next)
188 if (match_xsd_string(ptr, "recordSchema", o,
191 else if (match_xsd_string(ptr, "recordPacking", o, &spack))
193 if (spack && !strcmp(spack, "xml"))
194 pack = Z_SRW_recordPacking_XML;
195 if (spack && !strcmp(spack, "string"))
196 pack = Z_SRW_recordPacking_string;
198 else if (match_xsd_integer(ptr, "recordPosition", o,
199 &rec->recordPosition))
203 if (pack == Z_SRW_recordPacking_XML)
204 match_xsd_XML_n(ptr, "recordData", o,
205 &rec->recordData_buf,
206 &rec->recordData_len);
207 if (pack == Z_SRW_recordPacking_string)
208 match_xsd_string_n(ptr, "recordData", o,
209 &rec->recordData_buf,
210 &rec->recordData_len);
213 rec->recordPacking = pack;
215 else if (o->direction == ODR_ENCODE)
217 xmlNodePtr ptr = pptr;
218 add_xsd_string(ptr, "recordSchema", rec->recordSchema);
219 switch(rec->recordPacking)
221 case Z_SRW_recordPacking_string:
222 add_xsd_string(ptr, "recordPacking", "string");
223 add_xsd_string_n(ptr, "recordData", rec->recordData_buf,
224 rec->recordData_len);
226 case Z_SRW_recordPacking_XML:
227 add_xsd_string(ptr, "recordPacking", "xml");
228 add_XML_n(ptr, "recordData", rec->recordData_buf,
229 rec->recordData_len);
232 add_xsd_integer(ptr, "recordPosition", rec->recordPosition);
237 static int yaz_srw_records(ODR o, xmlNodePtr pptr, Z_SRW_record **recs,
238 int *num, void *client_data, const char *ns)
240 if (o->direction == ODR_DECODE)
245 for (ptr = pptr->children; ptr; ptr = ptr->next)
247 if (ptr->type == XML_ELEMENT_NODE &&
248 !strcmp(ptr->name, "record"))
253 *recs = (Z_SRW_record *) odr_malloc(o, *num * sizeof(**recs));
254 for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next)
256 if (ptr->type == XML_ELEMENT_NODE &&
257 !strcmp(ptr->name, "record"))
259 yaz_srw_record(o, ptr, (*recs)+i, client_data, ns);
264 else if (o->direction == ODR_ENCODE)
267 for (i = 0; i < *num; i++)
269 xmlNodePtr rptr = xmlNewChild(pptr, 0, "record", 0);
270 yaz_srw_record(o, rptr, (*recs)+i, client_data, ns);
276 static int yaz_srw_diagnostics(ODR o, xmlNodePtr pptr, Z_SRW_diagnostic **recs,
277 int *num, void *client_data, const char *ns)
279 if (o->direction == ODR_DECODE)
284 for (ptr = pptr->children; ptr; ptr = ptr->next)
286 if (ptr->type == XML_ELEMENT_NODE &&
287 !strcmp(ptr->name, "diagnostic"))
292 *recs = (Z_SRW_diagnostic *) odr_malloc(o, *num * sizeof(**recs));
293 for (i = 0; i < *num; i++)
296 (*recs)[i].details = 0;
297 (*recs)[i].message = 0;
299 for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next)
301 if (ptr->type == XML_ELEMENT_NODE &&
302 !strcmp(ptr->name, "diagnostic"))
306 (*recs)[i].details = 0;
307 (*recs)[i].message = 0;
308 for (rptr = ptr->children; rptr; rptr = rptr->next)
310 if (match_xsd_string(rptr, "uri", o,
313 else if (match_xsd_string(rptr, "details", o,
314 &(*recs)[i].details))
316 else if (match_xsd_string(rptr, "message", o,
317 &(*recs)[i].message))
324 else if (o->direction == ODR_ENCODE)
328 xmlNewNs(pptr, "http://www.loc.gov/zing/srw/diagnostic/", 0);
329 for (i = 0; i < *num; i++)
331 const char *std_diag = "info:srw/diagnostic/1/";
332 xmlNodePtr rptr = xmlNewChild(pptr, ns_diag, "diagnostic", 0);
333 add_xsd_string(rptr, "uri", (*recs)[i].uri);
334 if ((*recs)[i].message)
335 add_xsd_string(rptr, "message", (*recs)[i].message);
336 else if ((*recs)[i].uri &&
337 !strncmp((*recs)[i].uri, std_diag, strlen(std_diag)))
339 int no = atoi((*recs)[i].uri + strlen(std_diag));
340 const char *message = yaz_diag_srw_str(no);
342 add_xsd_string(rptr, "message", message);
344 add_xsd_string(rptr, "details", (*recs)[i].details);
350 static int yaz_srw_term(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm *term,
351 void *client_data, const char *ns)
353 if (o->direction == ODR_DECODE)
357 term->numberOfRecords = 0;
358 term->displayTerm = 0;
359 term->whereInList = 0;
360 for (ptr = pptr->children; ptr; ptr = ptr->next)
362 if (match_xsd_string(ptr, "value", o, &term->value))
364 else if (match_xsd_integer(ptr, "numberOfRecords", o,
365 &term->numberOfRecords))
367 else if (match_xsd_string(ptr, "displayTerm", o,
370 else if (match_xsd_string(ptr, "whereInList", o,
375 else if (o->direction == ODR_ENCODE)
377 xmlNodePtr ptr = pptr;
378 add_xsd_string(ptr, "value", term->value);
379 add_xsd_integer(ptr, "numberOfRecords", term->numberOfRecords);
380 add_xsd_string(ptr, "displayTerm", term->displayTerm);
381 add_xsd_string(ptr, "whereInList", term->whereInList);
386 static int yaz_srw_terms(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm **terms,
387 int *num, void *client_data, const char *ns)
389 if (o->direction == ODR_DECODE)
394 for (ptr = pptr->children; ptr; ptr = ptr->next)
396 if (ptr->type == XML_ELEMENT_NODE &&
397 !strcmp(ptr->name, "term"))
402 *terms = (Z_SRW_scanTerm *) odr_malloc(o, *num * sizeof(**terms));
403 for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
405 if (ptr->type == XML_ELEMENT_NODE &&
406 !strcmp(ptr->name, "term"))
407 yaz_srw_term(o, ptr, (*terms)+i, client_data, ns);
410 else if (o->direction == ODR_ENCODE)
413 for (i = 0; i < *num; i++)
415 xmlNodePtr rptr = xmlNewChild(pptr, 0, "term", 0);
416 yaz_srw_term(o, rptr, (*terms)+i, client_data, ns);
422 int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
423 void *client_data, const char *ns)
425 xmlNodePtr pptr = (xmlNodePtr) vptr;
426 if (o->direction == ODR_DECODE)
428 Z_SRW_PDU **p = handler_data;
429 xmlNodePtr method = pptr->children;
431 while (method && method->type == XML_TEXT_NODE)
432 method = method->next;
436 if (method->type != XML_ELEMENT_NODE)
439 *p = (Z_SRW_PDU *) odr_malloc(o, sizeof(**p));
440 (*p)->srw_version = odr_strdup(o, "1.1");
442 if (!strcmp(method->name, "searchRetrieveRequest"))
444 xmlNodePtr ptr = method->children;
445 Z_SRW_searchRetrieveRequest *req;
447 (*p)->which = Z_SRW_searchRetrieve_request;
448 req = (*p)->u.request = (Z_SRW_searchRetrieveRequest *)
449 odr_malloc(o, sizeof(*req));
450 req->query_type = Z_SRW_query_type_cql;
452 req->sort_type = Z_SRW_sort_type_none;
454 req->startRecord = 0;
455 req->maximumRecords = 0;
456 req->recordSchema = 0;
457 req->recordPacking = 0;
458 req->recordXPath = 0;
459 req->resultSetTTL = 0;
463 for (; ptr; ptr = ptr->next)
465 if (match_xsd_string(ptr, "version", o,
468 else if (match_xsd_string(ptr, "query", o,
470 req->query_type = Z_SRW_query_type_cql;
471 else if (match_xsd_string(ptr, "pQuery", o,
473 req->query_type = Z_SRW_query_type_pqf;
474 else if (match_xsd_string(ptr, "xQuery", o,
476 req->query_type = Z_SRW_query_type_xcql;
477 else if (match_xsd_integer(ptr, "startRecord", o,
480 else if (match_xsd_integer(ptr, "maximumRecords", o,
481 &req->maximumRecords))
483 else if (match_xsd_string(ptr, "recordPacking", o,
484 &req->recordPacking))
486 else if (match_xsd_string(ptr, "recordSchema", o,
489 else if (match_xsd_string(ptr, "recordXPath", o,
492 else if (match_xsd_string(ptr, "resultSetTTL", o,
495 else if (match_xsd_string(ptr, "sortKeys", o,
496 &req->sort.sortKeys))
497 req->sort_type = Z_SRW_sort_type_sort;
498 else if (match_xsd_string(ptr, "stylesheet", o,
501 else if (match_xsd_string(ptr, "database", o,
504 /* missing is xQuery, xSortKeys .. */
507 else if (!strcmp(method->name, "searchRetrieveResponse"))
509 xmlNodePtr ptr = method->children;
510 Z_SRW_searchRetrieveResponse *res;
512 (*p)->which = Z_SRW_searchRetrieve_response;
513 res = (*p)->u.response = (Z_SRW_searchRetrieveResponse *)
514 odr_malloc(o, sizeof(*res));
516 res->numberOfRecords = 0;
517 res->resultSetId = 0;
518 res->resultSetIdleTime = 0;
520 res->num_records = 0;
521 res->diagnostics = 0;
522 res->num_diagnostics = 0;
523 res->nextRecordPosition = 0;
525 for (; ptr; ptr = ptr->next)
527 if (match_xsd_string(ptr, "version", o,
530 else if (match_xsd_integer(ptr, "numberOfRecords", o,
531 &res->numberOfRecords))
533 else if (match_xsd_string(ptr, "resultSetId", o,
536 else if (match_xsd_integer(ptr, "resultSetIdleTime", o,
537 &res->resultSetIdleTime))
539 else if (match_element(ptr, "records"))
540 yaz_srw_records(o, ptr, &res->records,
541 &res->num_records, client_data,
543 else if (match_xsd_integer(ptr, "nextRecordPosition", o,
544 &res->nextRecordPosition))
546 else if (match_element(ptr, "diagnostics"))
547 yaz_srw_diagnostics(o, ptr, &res->diagnostics,
548 &res->num_diagnostics,
552 else if (!strcmp(method->name, "explainRequest"))
554 Z_SRW_explainRequest *req;
555 xmlNodePtr ptr = method->children;
557 (*p)->which = Z_SRW_explain_request;
558 req = (*p)->u.explain_request = (Z_SRW_explainRequest *)
559 odr_malloc(o, sizeof(*req));
560 req->recordPacking = 0;
563 for (; ptr; ptr = ptr->next)
565 if (match_xsd_string(ptr, "version", o,
568 else if (match_xsd_string(ptr, "stylesheet", o,
571 else if (match_xsd_string(ptr, "recordPacking", o,
572 &req->recordPacking))
574 else if (match_xsd_string(ptr, "database", o,
579 else if (!strcmp(method->name, "explainResponse"))
581 Z_SRW_explainResponse *res;
582 xmlNodePtr ptr = method->children;
584 (*p)->which = Z_SRW_explain_response;
585 res = (*p)->u.explain_response = (Z_SRW_explainResponse*)
586 odr_malloc(o, sizeof(*res));
587 res->diagnostics = 0;
588 res->num_diagnostics = 0;
589 res->record.recordSchema = 0;
590 res->record.recordData_buf = 0;
591 res->record.recordData_len = 0;
592 res->record.recordPosition = 0;
594 for (; ptr; ptr = ptr->next)
596 if (match_xsd_string(ptr, "version", o,
599 else if (match_element(ptr, "record"))
600 yaz_srw_record(o, ptr, &res->record, client_data, ns);
601 else if (match_element(ptr, "diagnostics"))
602 yaz_srw_diagnostics(o, ptr, &res->diagnostics,
603 &res->num_diagnostics,
608 else if (!strcmp(method->name, "scanRequest"))
610 Z_SRW_scanRequest *req;
611 xmlNodePtr ptr = method->children;
613 (*p)->which = Z_SRW_scan_request;
614 req = (*p)->u.scan_request = (Z_SRW_scanRequest *)
615 odr_malloc(o, sizeof(*req));
616 req->query_type = Z_SRW_query_type_cql;
617 req->scanClause.cql = 0;
618 req->responsePosition = 0;
619 req->maximumTerms = 0;
623 for (; ptr; ptr = ptr->next)
625 if (match_xsd_string(ptr, "version", o,
628 else if (match_xsd_string(ptr, "scanClause", o,
629 &req->scanClause.cql))
631 else if (match_xsd_string(ptr, "pScanClause", o,
632 &req->scanClause.pqf))
634 req->query_type = Z_SRW_query_type_pqf;
636 else if (match_xsd_integer(ptr, "responsePosition", o,
637 &req->responsePosition))
639 else if (match_xsd_integer(ptr, "maximumTerms", o,
642 else if (match_xsd_string(ptr, "stylesheet", o,
645 else if (match_xsd_string(ptr, "database", o,
650 else if (!strcmp(method->name, "scanResponse"))
652 Z_SRW_scanResponse *res;
653 xmlNodePtr ptr = method->children;
655 (*p)->which = Z_SRW_scan_response;
656 res = (*p)->u.scan_response = (Z_SRW_scanResponse *)
657 odr_malloc(o, sizeof(*res));
660 res->diagnostics = 0;
661 res->num_diagnostics = 0;
663 for (; ptr; ptr = ptr->next)
665 if (match_xsd_string(ptr, "version", o,
668 else if (match_element(ptr, "terms"))
669 yaz_srw_terms(o, ptr, &res->terms,
670 &res->num_terms, client_data,
672 else if (match_element(ptr, "diagnostics"))
673 yaz_srw_diagnostics(o, ptr, &res->diagnostics,
674 &res->num_diagnostics,
684 else if (o->direction == ODR_ENCODE)
686 Z_SRW_PDU **p = handler_data;
689 if ((*p)->which == Z_SRW_searchRetrieve_request)
691 Z_SRW_searchRetrieveRequest *req = (*p)->u.request;
692 xmlNodePtr ptr = xmlNewChild(pptr, 0,
693 "searchRetrieveRequest", 0);
694 ns_srw = xmlNewNs(ptr, ns, "zs");
695 xmlSetNs(ptr, ns_srw);
697 if ((*p)->srw_version)
698 add_xsd_string(ptr, "version", (*p)->srw_version);
699 switch(req->query_type)
701 case Z_SRW_query_type_cql:
702 add_xsd_string(ptr, "query", req->query.cql);
704 case Z_SRW_query_type_xcql:
705 add_xsd_string(ptr, "xQuery", req->query.xcql);
707 case Z_SRW_query_type_pqf:
708 add_xsd_string(ptr, "pQuery", req->query.pqf);
711 add_xsd_integer(ptr, "startRecord", req->startRecord);
712 add_xsd_integer(ptr, "maximumRecords", req->maximumRecords);
713 add_xsd_string(ptr, "recordPacking", req->recordPacking);
714 add_xsd_string(ptr, "recordSchema", req->recordSchema);
715 add_xsd_string(ptr, "recordXPath", req->recordXPath);
716 add_xsd_integer(ptr, "resultSetTTL", req->resultSetTTL);
717 switch(req->sort_type)
719 case Z_SRW_sort_type_none:
721 case Z_SRW_sort_type_sort:
722 add_xsd_string(ptr, "sortKeys", req->sort.sortKeys);
724 case Z_SRW_sort_type_xSort:
725 add_xsd_string(ptr, "xSortKeys", req->sort.xSortKeys);
728 add_xsd_string(ptr, "stylesheet", req->stylesheet);
729 add_xsd_string(ptr, "database", req->database);
731 else if ((*p)->which == Z_SRW_searchRetrieve_response)
733 Z_SRW_searchRetrieveResponse *res = (*p)->u.response;
734 xmlNodePtr ptr = xmlNewChild(pptr, 0,
735 "searchRetrieveResponse", 0);
736 ns_srw = xmlNewNs(ptr, ns, "zs");
737 xmlSetNs(ptr, ns_srw);
739 if ((*p)->srw_version)
740 add_xsd_string(ptr, "version", (*p)->srw_version);
741 add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
742 add_xsd_string(ptr, "resultSetId", res->resultSetId);
743 add_xsd_integer(ptr, "resultSetIdleTime", res->resultSetIdleTime);
744 if (res->num_records)
746 xmlNodePtr rptr = xmlNewChild(ptr, 0, "records", 0);
747 yaz_srw_records(o, rptr, &res->records, &res->num_records,
750 add_xsd_integer(ptr, "nextRecordPosition",
751 res->nextRecordPosition);
752 if (res->num_diagnostics)
754 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
755 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
756 &res->num_diagnostics, client_data, ns);
759 else if ((*p)->which == Z_SRW_explain_request)
761 Z_SRW_explainRequest *req = (*p)->u.explain_request;
762 xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainRequest", 0);
763 ns_srw = xmlNewNs(ptr, ns, "zs");
764 xmlSetNs(ptr, ns_srw);
766 add_xsd_string(ptr, "version", (*p)->srw_version);
767 add_xsd_string(ptr, "recordPacking", req->recordPacking);
768 add_xsd_string(ptr, "stylesheet", req->stylesheet);
769 add_xsd_string(ptr, "database", req->database);
771 else if ((*p)->which == Z_SRW_explain_response)
773 Z_SRW_explainResponse *res = (*p)->u.explain_response;
774 xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainResponse", 0);
775 ns_srw = xmlNewNs(ptr, ns, "zs");
776 xmlSetNs(ptr, ns_srw);
778 add_xsd_string(ptr, "version", (*p)->srw_version);
781 xmlNodePtr ptr1 = xmlNewChild(ptr, 0, "record", 0);
782 yaz_srw_record(o, ptr1, &res->record, client_data, ns);
784 if (res->num_diagnostics)
786 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
787 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
788 &res->num_diagnostics, client_data, ns);
791 else if ((*p)->which == Z_SRW_scan_request)
793 Z_SRW_scanRequest *req = (*p)->u.scan_request;
794 xmlNodePtr ptr = xmlNewChild(pptr, 0, "scanRequest", 0);
795 ns_srw = xmlNewNs(ptr, ns, "zs");
796 xmlSetNs(ptr, ns_srw);
798 add_xsd_string(ptr, "version", (*p)->srw_version);
799 switch(req->query_type)
801 case Z_SRW_query_type_cql:
802 add_xsd_string(ptr, "scanClause", req->scanClause.cql);
804 case Z_SRW_query_type_pqf:
805 add_xsd_string(ptr, "pScanClause", req->scanClause.pqf);
808 add_xsd_integer(ptr, "responsePosition", req->responsePosition);
809 add_xsd_integer(ptr, "maximumTerms", req->maximumTerms);
810 add_xsd_string(ptr, "stylesheet", req->stylesheet);
811 add_xsd_string(ptr, "database", req->database);
813 else if ((*p)->which == Z_SRW_scan_response)
815 Z_SRW_scanResponse *res = (*p)->u.scan_response;
816 xmlNodePtr ptr = xmlNewChild(pptr, 0, "scanResponse", 0);
817 ns_srw = xmlNewNs(ptr, ns, "zs");
818 xmlSetNs(ptr, ns_srw);
820 add_xsd_string(ptr, "version", (*p)->srw_version);
824 xmlNodePtr rptr = xmlNewChild(ptr, 0, "terms", 0);
825 yaz_srw_terms(o, rptr, &res->terms, &res->num_terms,
828 if (res->num_diagnostics)
830 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
831 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
832 &res->num_diagnostics, client_data, ns);