2 * Copyright (c) 2002-2004, Index Data.
3 * See the file LICENSE for details.
5 * $Id: srw.c,v 1.13 2004-01-05 14:46:52 adam Exp $
11 #include <libxml/parser.h>
12 #include <libxml/tree.h>
14 static void add_XML_n(xmlNodePtr ptr, const char *elem, char *val, int len)
18 xmlDocPtr doc = xmlParseMemory(val,len);
21 xmlNodePtr c = xmlNewChild(ptr, 0, elem, 0);
22 xmlNodePtr t = xmlDocGetRootElement(doc);
23 xmlAddChild(c, xmlCopyNode(t,1));
29 xmlNodePtr add_xsd_string_n(xmlNodePtr ptr, const char *elem, char *val,
34 xmlNodePtr c = xmlNewChild(ptr, 0, elem, 0);
35 xmlNodePtr t = xmlNewTextLen(val, len);
42 xmlNodePtr add_xsd_string(xmlNodePtr ptr, const char *elem, char *val)
45 return xmlNewChild(ptr, 0, elem, val);
49 static void add_xsd_integer(xmlNodePtr ptr, const char *elem, int *val)
54 sprintf(str, "%d", *val);
55 xmlNewChild(ptr, 0, elem, str);
59 static int match_element(xmlNodePtr ptr, const char *elem)
61 if (ptr->type == XML_ELEMENT_NODE && !strcmp(ptr->name, elem))
68 static int match_xsd_string_n(xmlNodePtr ptr, const char *elem, ODR o,
72 struct _xmlAttr *attr;
74 if (!match_element(ptr, elem))
77 for (attr = ptr->properties; attr; attr = attr->next)
78 if (!strcmp(attr->name, "type") &&
79 attr->children && attr->children->type == XML_TEXT_NODE)
81 const char *t = strchr(attr->children->content, ':');
85 t = attr->children->content;
86 if (!strcmp(t, "string"))
93 if (!ptr || ptr->type != XML_TEXT_NODE)
95 *val = odr_strdup(o, ptr->content);
97 *len = strlen(ptr->content);
102 static int match_xsd_string(xmlNodePtr ptr, const char *elem, ODR o,
105 return match_xsd_string_n(ptr, elem, o, val, 0);
108 static int match_xsd_XML_n(xmlNodePtr ptr, const char *elem, ODR o,
109 char **val, int *len)
113 if (!match_element(ptr, elem))
118 buf = xmlBufferCreate();
120 xmlNodeDump(buf, ptr->doc, ptr, 0, 0);
122 *val = odr_malloc(o, buf->use+1);
123 memcpy (*val, buf->content, buf->use);
124 (*val)[buf->use] = '\0';
135 static int match_xsd_integer(xmlNodePtr ptr, const char *elem, ODR o, int **val)
138 struct _xmlAttr *attr;
140 if (!match_element(ptr, elem))
143 for (attr = ptr->properties; attr; attr = attr->next)
144 if (!strcmp(attr->name, "type") &&
145 attr->children && attr->children->type == XML_TEXT_NODE)
147 const char *t = strchr(attr->children->content, ':');
151 t = attr->children->content;
152 if (!strcmp(t, "integer"))
159 if (!ptr || ptr->type != XML_TEXT_NODE)
161 *val = odr_intdup(o, atoi(ptr->content));
165 static int yaz_srw_record(ODR o, xmlNodePtr pptr, Z_SRW_record *rec,
166 void *client_data, const char *ns)
168 if (o->direction == ODR_DECODE)
170 int pack = Z_SRW_recordPacking_string;
172 rec->recordSchema = 0;
173 rec->recordData_buf = 0;
174 rec->recordData_len = 0;
175 rec->recordPosition = 0;
176 for (ptr = pptr->children; ptr; ptr = ptr->next)
180 if (match_xsd_string(ptr, "recordSchema", o,
183 else if (match_xsd_string(ptr, "recordPacking", o, &spack))
185 if (pack && !strcmp(spack, "xml"))
186 pack = Z_SRW_recordPacking_XML;
187 if (pack && !strcmp(spack, "string"))
188 pack = Z_SRW_recordPacking_string;
190 else if (match_xsd_integer(ptr, "recordPosition", o,
191 &rec->recordPosition))
195 if (pack == Z_SRW_recordPacking_XML)
196 match_xsd_XML_n(ptr, "recordData", o,
197 &rec->recordData_buf,
198 &rec->recordData_len);
199 if (pack == Z_SRW_recordPacking_string)
200 match_xsd_string_n(ptr, "recordData", o,
201 &rec->recordData_buf,
202 &rec->recordData_len);
205 rec->recordPacking = pack;
207 else if (o->direction == ODR_ENCODE)
209 xmlNodePtr ptr = pptr;
210 add_xsd_string(ptr, "recordSchema", rec->recordSchema);
211 switch(rec->recordPacking)
213 case Z_SRW_recordPacking_string:
214 add_xsd_string(ptr, "recordPacking", "string");
215 add_xsd_string_n(ptr, "recordData", rec->recordData_buf,
216 rec->recordData_len);
218 case Z_SRW_recordPacking_XML:
219 add_xsd_string(ptr, "recordPacking", "xml");
220 add_XML_n(ptr, "recordData", rec->recordData_buf,
221 rec->recordData_len);
224 add_xsd_integer(ptr, "recordPosition", rec->recordPosition);
229 static int yaz_srw_records(ODR o, xmlNodePtr pptr, Z_SRW_record **recs,
230 int *num, void *client_data, const char *ns)
232 if (o->direction == ODR_DECODE)
237 for (ptr = pptr->children; ptr; ptr = ptr->next)
239 if (ptr->type == XML_ELEMENT_NODE &&
240 !strcmp(ptr->name, "record"))
245 *recs = odr_malloc(o, *num * sizeof(**recs));
246 for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
248 if (ptr->type == XML_ELEMENT_NODE &&
249 !strcmp(ptr->name, "record"))
250 yaz_srw_record(o, ptr, (*recs)+i, client_data, ns);
253 else if (o->direction == ODR_ENCODE)
256 for (i = 0; i < *num; i++)
258 xmlNodePtr rptr = xmlNewChild(pptr, 0, "record", 0);
259 yaz_srw_record(o, rptr, (*recs)+i, client_data, ns);
265 static int yaz_srw_diagnostics(ODR o, xmlNodePtr pptr, Z_SRW_diagnostic **recs,
266 int *num, void *client_data, const char *ns)
268 if (o->direction == ODR_DECODE)
273 for (ptr = pptr->children; ptr; ptr = ptr->next)
275 if (ptr->type == XML_ELEMENT_NODE &&
276 !strcmp(ptr->name, "diagnostic"))
281 *recs = odr_malloc(o, *num * sizeof(**recs));
282 for (i = 0; i < *num; i++)
285 (*recs)[i].details = 0;
287 for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next)
289 if (ptr->type == XML_ELEMENT_NODE &&
290 !strcmp(ptr->name, "diagnostic"))
294 (*recs)[i].details = 0;
295 for (rptr = ptr->children; rptr; rptr = rptr->next)
297 if (match_xsd_integer(rptr, "code", o,
300 else if (match_xsd_string(rptr, "details", o,
301 &(*recs)[i].details))
308 else if (o->direction == ODR_ENCODE)
312 xmlNewNs(pptr, "http://www.loc.gov/zing/srw/diagnostics/", "diag");
313 for (i = 0; i < *num; i++)
315 xmlNodePtr rptr = xmlNewChild(pptr, ns_diag, "diagnostic", 0);
316 add_xsd_integer(rptr, "code", (*recs)[i].code);
317 add_xsd_string(rptr, "details", (*recs)[i].details);
323 static int yaz_srw_term(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm *term,
324 void *client_data, const char *ns)
326 if (o->direction == ODR_DECODE)
330 term->numberOfRecords = 0;
331 term->displayTerm = 0;
332 for (ptr = pptr->children; ptr; ptr = ptr->next)
334 if (match_xsd_string(ptr, "value", o, &term->value))
336 else if (match_xsd_integer(ptr, "numberOfRecords", o,
337 &term->numberOfRecords))
339 else if (match_xsd_string(ptr, "displayTerm", o,
344 else if (o->direction == ODR_ENCODE)
346 xmlNodePtr ptr = pptr;
347 add_xsd_string(ptr, "value", term->value);
348 add_xsd_integer(ptr, "value", term->numberOfRecords);
349 add_xsd_string(ptr, "displayTerm", term->displayTerm);
354 static int yaz_srw_terms(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm **terms,
355 int *num, void *client_data, const char *ns)
357 if (o->direction == ODR_DECODE)
362 for (ptr = pptr->children; ptr; ptr = ptr->next)
364 if (ptr->type == XML_ELEMENT_NODE &&
365 !strcmp(ptr->name, "term"))
370 *terms = odr_malloc(o, *num * sizeof(**terms));
371 for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
373 if (ptr->type == XML_ELEMENT_NODE &&
374 !strcmp(ptr->name, "term"))
375 yaz_srw_term(o, ptr, (*terms)+i, client_data, ns);
378 else if (o->direction == ODR_ENCODE)
381 for (i = 0; i < *num; i++)
383 xmlNodePtr rptr = xmlNewChild(pptr, 0, "term", 0);
384 yaz_srw_term(o, rptr, (*terms)+i, client_data, ns);
390 int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
391 void *client_data, const char *ns)
393 xmlNodePtr pptr = vptr;
394 if (o->direction == ODR_DECODE)
396 Z_SRW_PDU **p = handler_data;
397 xmlNodePtr method = pptr->children;
399 while (method && method->type == XML_TEXT_NODE)
400 method = method->next;
404 if (method->type != XML_ELEMENT_NODE)
407 *p = odr_malloc(o, sizeof(**p));
408 (*p)->srw_version = odr_strdup(o, "1.1");
410 if (!strcmp(method->name, "searchRetrieveRequest"))
412 xmlNodePtr ptr = method->children;
413 Z_SRW_searchRetrieveRequest *req;
415 (*p)->which = Z_SRW_searchRetrieve_request;
416 req = (*p)->u.request = odr_malloc(o, sizeof(*req));
417 req->query_type = Z_SRW_query_type_cql;
419 req->sort_type = Z_SRW_sort_type_none;
421 req->startRecord = 0;
422 req->maximumRecords = 0;
423 req->recordSchema = 0;
424 req->recordPacking = 0;
425 req->recordXPath = 0;
426 req->resultSetTTL = 0;
430 for (; ptr; ptr = ptr->next)
432 if (match_xsd_string(ptr, "query", o,
434 req->query_type = Z_SRW_query_type_cql;
435 else if (match_xsd_string(ptr, "pQuery", o,
437 req->query_type = Z_SRW_query_type_pqf;
438 else if (match_xsd_string(ptr, "xQuery", o,
440 req->query_type = Z_SRW_query_type_xcql;
441 else if (match_xsd_string(ptr, "sortKeys", o,
442 &req->sort.sortKeys))
443 req->sort_type = Z_SRW_sort_type_sort;
444 else if (match_xsd_string(ptr, "recordSchema", o,
447 else if (match_xsd_string(ptr, "recordPacking", o,
448 &req->recordPacking))
450 else if (match_xsd_string(ptr, "recordXPath", o,
453 else if (match_xsd_integer(ptr, "startRecord", o,
456 else if (match_xsd_integer(ptr, "maximumRecords", o,
457 &req->maximumRecords))
459 else if (match_xsd_string(ptr, "stylesheet", o,
462 else if (match_xsd_string(ptr, "database", o,
465 else if (match_xsd_string(ptr, "resultSetTTL", o,
468 else if (match_xsd_string(ptr, "version", o,
471 /* missing is xQuery, xSortKeys .. */
474 else if (!strcmp(method->name, "searchRetrieveResponse"))
476 xmlNodePtr ptr = method->children;
477 Z_SRW_searchRetrieveResponse *res;
479 (*p)->which = Z_SRW_searchRetrieve_response;
480 res = (*p)->u.response = odr_malloc(o, sizeof(*res));
482 res->numberOfRecords = 0;
483 res->resultSetId = 0;
484 res->resultSetIdleTime = 0;
486 res->num_records = 0;
487 res->diagnostics = 0;
488 res->num_diagnostics = 0;
489 res->nextRecordPosition = 0;
491 for (; ptr; ptr = ptr->next)
493 if (match_xsd_integer(ptr, "numberOfRecords", o,
494 &res->numberOfRecords))
496 else if (match_xsd_string(ptr, "resultSetId", o,
499 else if (match_xsd_integer(ptr, "resultSetIdleTime", o,
500 &res->resultSetIdleTime))
502 else if (match_element(ptr, "records"))
503 yaz_srw_records(o, ptr, &res->records,
504 &res->num_records, client_data,
506 else if (match_element(ptr, "diagnostics"))
507 yaz_srw_diagnostics(o, ptr, &res->diagnostics,
508 &res->num_diagnostics,
510 else if (match_xsd_integer(ptr, "nextRecordPosition", o,
511 &res->nextRecordPosition))
513 else if (match_xsd_string(ptr, "version", o,
518 else if (!strcmp(method->name, "explainRequest"))
520 Z_SRW_explainRequest *req;
521 xmlNodePtr ptr = method->children;
523 (*p)->which = Z_SRW_explain_request;
524 req = (*p)->u.explain_request = odr_malloc(o, sizeof(*req));
525 req->recordPacking = 0;
527 for (; ptr; ptr = ptr->next)
529 if (match_xsd_string(ptr, "database", o,
532 else if (match_xsd_string(ptr, "recordPacking", o,
533 &req->recordPacking))
535 else if (match_xsd_string(ptr, "version", o,
540 else if (!strcmp(method->name, "explainResponse"))
542 Z_SRW_explainResponse *res;
543 xmlNodePtr ptr = method->children;
545 (*p)->which = Z_SRW_explain_response;
546 res = (*p)->u.explain_response = odr_malloc(o, sizeof(*res));
547 res->diagnostics = 0;
548 res->num_diagnostics = 0;
550 for (; ptr; ptr = ptr->next)
552 if (match_element(ptr, "record"))
553 yaz_srw_record(o, ptr, &res->record, client_data, ns);
554 else if (match_xsd_string(ptr, "version", o,
557 else if (match_element(ptr, "diagnostics"))
558 yaz_srw_diagnostics(o, ptr, &res->diagnostics,
559 &res->num_diagnostics,
564 else if (!strcmp(method->name, "scanRequest"))
566 Z_SRW_scanRequest *req;
567 xmlNodePtr ptr = method->children;
569 (*p)->which = Z_SRW_scan_request;
570 req = (*p)->u.scan_request = odr_malloc(o, sizeof(*req));
574 req->responsePosition = 0;
575 req->maximumTerms = 0;
577 for (; ptr; ptr = ptr->next)
579 if (match_xsd_string(ptr, "version", o,
582 else if (match_xsd_string(ptr, "scanClause", o,
585 else if (match_xsd_string(ptr, "database", o,
588 else if (match_xsd_string(ptr, "stylesheet", o,
591 else if (match_xsd_integer(ptr, "responsePosition", o,
592 &req->responsePosition))
594 else if (match_xsd_integer(ptr, "maximumTerms", o,
599 else if (!strcmp(method->name, "scanResponse"))
601 Z_SRW_scanResponse *res;
602 xmlNodePtr ptr = method->children;
604 (*p)->which = Z_SRW_scan_response;
605 res = (*p)->u.scan_response = odr_malloc(o, sizeof(*res));
608 res->diagnostics = 0;
609 res->num_diagnostics = 0;
611 for (; ptr; ptr = ptr->next)
613 if (match_element(ptr, "terms"))
614 yaz_srw_terms(o, ptr, &res->terms,
615 &res->num_terms, client_data,
617 else if (match_element(ptr, "diagnostics"))
618 yaz_srw_diagnostics(o, ptr, &res->diagnostics,
619 &res->num_diagnostics,
621 else if (match_xsd_string(ptr, "version", o,
632 else if (o->direction == ODR_ENCODE)
634 Z_SRW_PDU **p = handler_data;
637 if ((*p)->which == Z_SRW_searchRetrieve_request)
639 Z_SRW_searchRetrieveRequest *req = (*p)->u.request;
640 xmlNodePtr ptr = xmlNewChild(pptr, 0,
641 "searchRetrieveRequest", 0);
642 ns_srw = xmlNewNs(ptr, ns, "zs");
643 xmlSetNs(ptr, ns_srw);
645 if ((*p)->srw_version)
646 add_xsd_string(ptr, "version", (*p)->srw_version);
647 switch(req->query_type)
649 case Z_SRW_query_type_cql:
650 add_xsd_string(ptr, "query", req->query.cql);
652 case Z_SRW_query_type_xcql:
653 add_xsd_string(ptr, "xQuery", req->query.xcql);
655 case Z_SRW_query_type_pqf:
656 add_xsd_string(ptr, "pQuery", req->query.pqf);
659 switch(req->sort_type)
661 case Z_SRW_sort_type_none:
663 case Z_SRW_sort_type_sort:
664 add_xsd_string(ptr, "sortKeys", req->sort.sortKeys);
666 case Z_SRW_sort_type_xSort:
667 add_xsd_string(ptr, "xSortKeys", req->sort.xSortKeys);
670 add_xsd_integer(ptr, "startRecord", req->startRecord);
671 add_xsd_integer(ptr, "maximumRecords", req->maximumRecords);
672 add_xsd_string(ptr, "recordSchema", req->recordSchema);
673 add_xsd_string(ptr, "recordPacking", req->recordPacking);
674 add_xsd_string(ptr, "recordXPath", req->recordXPath);
675 add_xsd_string(ptr, "database", req->database);
676 add_xsd_integer(ptr, "resultSetTTL", req->resultSetTTL);
677 add_xsd_string(ptr, "stylesheet", req->stylesheet);
679 else if ((*p)->which == Z_SRW_searchRetrieve_response)
681 Z_SRW_searchRetrieveResponse *res = (*p)->u.response;
682 xmlNodePtr ptr = xmlNewChild(pptr, 0,
683 "searchRetrieveResponse", 0);
684 ns_srw = xmlNewNs(ptr, ns, "zs");
685 xmlSetNs(ptr, ns_srw);
687 if ((*p)->srw_version)
688 add_xsd_string(ptr, "version", (*p)->srw_version);
689 add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
690 add_xsd_string(ptr, "resultSetId", res->resultSetId);
691 add_xsd_integer(ptr, "resultSetIdleTime", res->resultSetIdleTime);
692 if (res->num_records)
694 xmlNodePtr rptr = xmlNewChild(ptr, 0, "records", 0);
695 yaz_srw_records(o, rptr, &res->records, &res->num_records,
698 if (res->num_diagnostics)
700 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
701 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
702 &res->num_diagnostics, client_data, ns);
704 add_xsd_integer(ptr, "nextRecordPosition", res->nextRecordPosition);
706 else if ((*p)->which == Z_SRW_explain_request)
708 xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainRequest", 0);
709 ns_srw = xmlNewNs(ptr, ns, "zs");
710 xmlSetNs(ptr, ns_srw);
712 add_xsd_string(ptr, "version", (*p)->srw_version);
714 else if ((*p)->which == Z_SRW_explain_response)
716 Z_SRW_explainResponse *res = (*p)->u.explain_response;
717 xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainResponse", 0);
718 ns_srw = xmlNewNs(ptr, ns, "zs");
719 xmlSetNs(ptr, ns_srw);
721 add_xsd_string(ptr, "version", (*p)->srw_version);
724 xmlNodePtr ptr1 = xmlNewChild(ptr, 0, "record", 0);
725 yaz_srw_record(o, ptr1, &res->record, client_data, ns);
727 if (res->num_diagnostics)
729 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
730 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
731 &res->num_diagnostics, client_data, ns);
734 else if ((*p)->which == Z_SRW_scan_request)
736 Z_SRW_scanRequest *req = (*p)->u.scan_request;
737 xmlNodePtr ptr = xmlNewChild(pptr, 0, "scanRequest", 0);
738 ns_srw = xmlNewNs(ptr, ns, "zs");
739 xmlSetNs(ptr, ns_srw);
741 add_xsd_string(ptr, "version", (*p)->srw_version);
742 add_xsd_string(ptr, "scanClause", req->scanClause);
743 add_xsd_integer(ptr, "responsePosition", req->responsePosition);
744 add_xsd_integer(ptr, "maximumTerms", req->maximumTerms);
745 add_xsd_string(ptr, "stylesheet", req->stylesheet);
747 else if ((*p)->which == Z_SRW_scan_response)
749 Z_SRW_scanResponse *res = (*p)->u.scan_response;
750 xmlNodePtr ptr = xmlNewChild(pptr, 0, "scanResponse", 0);
751 ns_srw = xmlNewNs(ptr, ns, "zs");
752 xmlSetNs(ptr, ns_srw);
754 add_xsd_string(ptr, "version", (*p)->srw_version);
758 xmlNodePtr rptr = xmlNewChild(ptr, 0, "terms", 0);
759 yaz_srw_terms(o, rptr, &res->terms, &res->num_terms,
762 if (res->num_diagnostics)
764 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
765 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
766 &res->num_diagnostics, client_data, ns);