1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2009 Index Data
3 * See the file LICENSE for details.
7 \brief Query / XML conversions
15 #include <libxml/parser.h>
16 #include <libxml/tree.h>
18 #include <yaz/logrpn.h>
19 #include <yaz/xmlquery.h>
20 #include <yaz/nmem_xml.h>
21 #include <yaz/oid_db.h>
23 static int check_diagnostic(const xmlNode *ptr, ODR odr,
24 int *error_code, const char **addinfo)
26 if (ptr && ptr->type == XML_ELEMENT_NODE &&
27 !xmlStrcmp(ptr->name, BAD_CAST "diagnostic"))
29 struct _xmlAttr *attr;
30 const char *code_str = 0;
31 const char *addinfo_str = 0;
32 for (attr = ptr->properties; attr; attr = attr->next)
34 if (!xmlStrcmp(attr->name, BAD_CAST "code") &&
35 attr->children && attr->children->type == XML_TEXT_NODE)
36 code_str = (const char *) attr->children->content;
37 else if (!xmlStrcmp(attr->name, BAD_CAST "addinfo") &&
38 attr->children && attr->children->type == XML_TEXT_NODE)
39 addinfo_str = (const char *) attr->children->content;
43 *addinfo = "bad attribute for diagnostic element";
50 *addinfo = "missing @code for diagnostic element";
53 *error_code = atoi(code_str);
55 *addinfo = odr_strdup(odr, addinfo_str);
62 static void yaz_query2xml_attribute_element(const Z_AttributeElement *element,
66 const char *setname = 0;
67 char oid_name_str[OID_STR_MAX];
69 if (element->attributeSet)
71 setname = yaz_oid_to_string_buf(element->attributeSet,
75 if (element->which == Z_AttributeValue_numeric)
77 xmlNodePtr node = xmlNewChild(parent, 0, BAD_CAST "attr", 0);
80 xmlNewProp(node, BAD_CAST "set", BAD_CAST setname);
82 assert(*element->attributeType > 0 && *element->attributeType < 20);
83 sprintf(formstr, ODR_INT_PRINTF, *element->attributeType);
84 xmlNewProp(node, BAD_CAST "type", BAD_CAST formstr);
86 sprintf(formstr, ODR_INT_PRINTF, *element->value.numeric);
87 xmlNewProp(node, BAD_CAST "value", BAD_CAST formstr);
89 else if (element->which == Z_AttributeValue_complex)
92 for (i = 0; i<element->value.complex->num_list; i++)
94 xmlNodePtr node = xmlNewChild(parent, 0, BAD_CAST "attr", 0);
97 xmlNewProp(node, BAD_CAST "set", BAD_CAST setname);
99 sprintf(formstr, ODR_INT_PRINTF, *element->attributeType);
100 xmlNewProp(node, BAD_CAST "type", BAD_CAST formstr);
102 if (element->value.complex->list[i]->which ==
103 Z_StringOrNumeric_string)
105 xmlNewProp(node, BAD_CAST "value", BAD_CAST
106 element->value.complex->list[i]->u.string);
108 else if (element->value.complex->list[i]->which ==
109 Z_StringOrNumeric_numeric)
111 sprintf(formstr, ODR_INT_PRINTF,
112 *element->value.complex->list[i]->u.numeric);
113 xmlNewProp(node, BAD_CAST "value", BAD_CAST formstr);
120 static xmlNodePtr yaz_query2xml_term(const Z_Term *term, xmlNodePtr parent)
123 xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "term", 0);
125 const char *type = 0;
131 t = xmlNewTextLen(BAD_CAST term->u.general->buf, term->u.general->len);
135 sprintf(formstr, ODR_INT_PRINTF, *term->u.numeric);
136 t = xmlNewText(BAD_CAST formstr);
138 case Z_Term_characterString:
140 t = xmlNewText(BAD_CAST term->u.characterString);
145 case Z_Term_dateTime:
148 case Z_Term_external:
151 case Z_Term_integerAndUnit:
152 type ="integerAndUnit";
160 if (t) /* got a term node ? */
161 xmlAddChild(node, t);
163 xmlNewProp(node, BAD_CAST "type", BAD_CAST type);
167 static xmlNodePtr yaz_query2xml_apt(const Z_AttributesPlusTerm *zapt,
170 xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "apt", 0);
171 int num_attributes = zapt->attributes->num_attributes;
173 for (i = 0; i<num_attributes; i++)
174 yaz_query2xml_attribute_element(zapt->attributes->attributes[i], node);
175 yaz_query2xml_term(zapt->term, node);
181 static void yaz_query2xml_operator(Z_Operator *op, xmlNodePtr node)
183 const char *type = 0;
192 case Z_Operator_and_not:
195 case Z_Operator_prox:
201 xmlNewProp(node, BAD_CAST "type", BAD_CAST type);
203 if (op->which == Z_Operator_prox)
207 if (op->u.prox->exclusion)
209 if (*op->u.prox->exclusion)
210 xmlNewProp(node, BAD_CAST "exclusion", BAD_CAST "true");
212 xmlNewProp(node, BAD_CAST "exclusion", BAD_CAST "false");
214 sprintf(formstr, ODR_INT_PRINTF, *op->u.prox->distance);
215 xmlNewProp(node, BAD_CAST "distance", BAD_CAST formstr);
217 if (*op->u.prox->ordered)
218 xmlNewProp(node, BAD_CAST "ordered", BAD_CAST "true");
220 xmlNewProp(node, BAD_CAST "ordered", BAD_CAST "false");
222 sprintf(formstr, ODR_INT_PRINTF, *op->u.prox->relationType);
223 xmlNewProp(node, BAD_CAST "relationType", BAD_CAST formstr);
225 switch(op->u.prox->which)
227 case Z_ProximityOperator_known:
228 sprintf(formstr, ODR_INT_PRINTF, *op->u.prox->u.known);
229 xmlNewProp(node, BAD_CAST "knownProximityUnit",
232 case Z_ProximityOperator_private:
234 xmlNewProp(node, BAD_CAST "privateProximityUnit",
241 static xmlNodePtr yaz_query2xml_rpnstructure(const Z_RPNStructure *zs,
244 if (zs->which == Z_RPNStructure_complex)
246 Z_Complex *zc = zs->u.complex;
248 xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "operator", 0);
250 yaz_query2xml_operator(zc->roperator, node);
251 yaz_query2xml_rpnstructure(zc->s1, node);
252 yaz_query2xml_rpnstructure(zc->s2, node);
255 else if (zs->which == Z_RPNStructure_simple)
257 if (zs->u.simple->which == Z_Operand_APT)
258 return yaz_query2xml_apt(zs->u.simple->u.attributesPlusTerm,
260 else if (zs->u.simple->which == Z_Operand_resultSetId)
261 return xmlNewChild(parent, /* NS */ 0, BAD_CAST "rset",
262 BAD_CAST zs->u.simple->u.resultSetId);
267 static xmlNodePtr yaz_query2xml_rpn(const Z_RPNQuery *rpn, xmlNodePtr parent)
269 if (rpn->attributeSetId)
271 char oid_name_str[OID_STR_MAX];
272 const char *setname = yaz_oid_to_string_buf(rpn->attributeSetId,
275 xmlNewProp(parent, BAD_CAST "set", BAD_CAST setname);
277 return yaz_query2xml_rpnstructure(rpn->RPNStructure, parent);
280 static xmlNodePtr yaz_query2xml_ccl(const Odr_oct *ccl, xmlNodePtr node)
285 static xmlNodePtr yaz_query2xml_z3958(const Odr_oct *ccl, xmlNodePtr node)
290 static xmlNodePtr yaz_query2xml_cql(const char *cql, xmlNodePtr node)
295 void yaz_rpnquery2xml(const Z_RPNQuery *rpn, xmlDocPtr *docp)
299 query.which = Z_Query_type_1;
300 query.u.type_1 = (Z_RPNQuery *) rpn;
301 yaz_query2xml(&query, docp);
304 void yaz_query2xml(const Z_Query *q, xmlDocPtr *docp)
306 xmlNodePtr top_node, q_node = 0, child_node = 0;
311 top_node = xmlNewNode(0, BAD_CAST "query");
316 case Z_Query_type_101:
317 q_node = xmlNewChild(top_node, 0, BAD_CAST "rpn", 0);
318 child_node = yaz_query2xml_rpn(q->u.type_1, q_node);
321 q_node = xmlNewChild(top_node, 0, BAD_CAST "ccl", 0);
322 child_node = yaz_query2xml_ccl(q->u.type_2, q_node);
324 case Z_Query_type_100:
325 q_node = xmlNewChild(top_node, 0, BAD_CAST "z39.58", 0);
326 child_node = yaz_query2xml_z3958(q->u.type_100, q_node);
328 case Z_Query_type_104:
329 if (q->u.type_104->which == Z_External_CQL)
331 q_node = xmlNewChild(top_node, 0, BAD_CAST "cql", 0);
332 child_node = yaz_query2xml_cql(q->u.type_104->u.cql, q_node);
335 if (child_node && q_node)
337 *docp = xmlNewDoc(BAD_CAST "1.0");
338 xmlDocSetRootElement(*docp, top_node); /* make it top node in doc */
343 xmlFreeNode(top_node);
347 static bool_t *boolVal(ODR odr, const char *str)
349 if (*str == '\0' || strchr("0fF", *str))
350 return odr_booldup(odr, 0);
351 return odr_booldup(odr, 1);
354 static Odr_int *intVal(ODR odr, const char *str)
356 return odr_intdup(odr, atoi(str));
359 static void yaz_xml2query_operator(const xmlNode *ptr, Z_Operator **op,
361 int *error_code, const char **addinfo)
363 const char *type = (const char *)
364 xmlGetProp((xmlNodePtr) ptr, BAD_CAST "type");
368 *addinfo = "no operator type";
371 *op = (Z_Operator*) odr_malloc(odr, sizeof(Z_Operator));
372 if (!strcmp(type, "and"))
374 (*op)->which = Z_Operator_and;
375 (*op)->u.op_and = odr_nullval();
377 else if (!strcmp(type, "or"))
379 (*op)->which = Z_Operator_or;
380 (*op)->u.op_or = odr_nullval();
382 else if (!strcmp(type, "not"))
384 (*op)->which = Z_Operator_and_not;
385 (*op)->u.and_not = odr_nullval();
387 else if (!strcmp(type, "prox"))
390 Z_ProximityOperator *pop = (Z_ProximityOperator *)
391 odr_malloc(odr, sizeof(Z_ProximityOperator));
393 (*op)->which = Z_Operator_prox;
396 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
397 BAD_CAST "exclusion");
399 pop->exclusion = boolVal(odr, atval);
403 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
404 BAD_CAST "distance");
406 pop->distance = intVal(odr, atval);
408 pop->distance = odr_intdup(odr, 1);
410 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
413 pop->ordered = boolVal(odr, atval);
415 pop->ordered = odr_booldup(odr, 1);
417 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
418 BAD_CAST "relationType");
420 pop->relationType = intVal(odr, atval);
423 odr_intdup(odr, Z_ProximityOperator_Prox_lessThanOrEqual);
425 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
426 BAD_CAST "knownProximityUnit");
429 pop->which = Z_ProximityOperator_known;
430 pop->u.known = intVal(odr, atval);
434 pop->which = Z_ProximityOperator_known;
435 pop->u.known = odr_intdup(odr, Z_ProxUnit_word);
438 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
439 BAD_CAST "privateProximityUnit");
442 pop->which = Z_ProximityOperator_private;
443 pop->u.zprivate = intVal(odr, atval);
449 *addinfo = "bad operator type";
453 static void yaz_xml2query_attribute_element(const xmlNode *ptr,
454 Z_AttributeElement **elem, ODR odr,
456 const char **addinfo)
463 struct _xmlAttr *attr;
464 for (attr = ptr->properties; attr; attr = attr->next)
466 if (!xmlStrcmp(attr->name, BAD_CAST "set") &&
467 attr->children && attr->children->type == XML_TEXT_NODE)
468 set = attr->children->content;
469 else if (!xmlStrcmp(attr->name, BAD_CAST "type") &&
470 attr->children && attr->children->type == XML_TEXT_NODE)
471 type = attr->children->content;
472 else if (!xmlStrcmp(attr->name, BAD_CAST "value") &&
473 attr->children && attr->children->type == XML_TEXT_NODE)
475 value = attr->children->content;
481 *addinfo = "bad attribute for attr content";
488 *addinfo = "missing type attribute for att content";
494 *addinfo = "missing value attribute for att content";
498 *elem = (Z_AttributeElement *) odr_malloc(odr, sizeof(**elem));
500 (*elem)->attributeSet = yaz_string_to_oid_odr(yaz_oid_std(),
505 (*elem)->attributeSet = 0;
506 (*elem)->attributeType = intVal(odr, (const char *) type);
508 /* looks like a number ? */
509 for (i = 0; value[i] && value[i] >= '0' && value[i] <= '9'; i++)
511 if (num_values > 1 || value[i])
512 { /* multiple values or string, so turn to complex attribute */
513 (*elem)->which = Z_AttributeValue_complex;
514 (*elem)->value.complex =
515 (Z_ComplexAttribute*) odr_malloc(odr, sizeof(Z_ComplexAttribute));
516 (*elem)->value.complex->num_list = num_values;
517 (*elem)->value.complex->list = (Z_StringOrNumeric **)
518 odr_malloc(odr, sizeof(Z_StringOrNumeric*) * num_values);
520 /* second pass over attr values */
522 for (attr = ptr->properties; attr; attr = attr->next)
524 if (!xmlStrcmp(attr->name, BAD_CAST "value") &&
525 attr->children && attr->children->type == XML_TEXT_NODE)
527 const char *val = (const char *) attr->children->content;
528 assert (i < num_values);
529 (*elem)->value.complex->list[i] = (Z_StringOrNumeric *)
530 odr_malloc(odr, sizeof(Z_StringOrNumeric));
531 (*elem)->value.complex->list[i]->which =
532 Z_StringOrNumeric_string;
533 (*elem)->value.complex->list[i]->u.string =
534 odr_strdup(odr, val);
538 (*elem)->value.complex->num_semanticAction = 0;
539 (*elem)->value.complex->semanticAction = 0;
542 { /* good'ld numeric value */
543 (*elem)->which = Z_AttributeValue_numeric;
544 (*elem)->value.numeric = intVal(odr, (const char *) value);
548 static char *strVal(const xmlNode *ptr_cdata, ODR odr)
550 return nmem_text_node_cdata(ptr_cdata, odr_getmem(odr));
553 static void yaz_xml2query_term(const xmlNode *ptr, Z_Term **term, ODR odr,
554 int *error_code, const char **addinfo)
557 struct _xmlAttr *attr;
558 char *cdata = strVal(ptr->children, odr);
560 for (attr = ptr->properties; attr; attr = attr->next)
562 if (!xmlStrcmp(attr->name, BAD_CAST "type") &&
563 attr->children && attr->children->type == XML_TEXT_NODE)
564 type = attr->children->content;
568 *addinfo = "bad attribute for attr content";
572 *term = (Z_Term *) odr_malloc(odr, sizeof(Z_Term));
574 if (!type || !xmlStrcmp(type, BAD_CAST "general"))
576 (*term)->which = Z_Term_general;
578 odr_create_Odr_oct(odr, (unsigned char *)cdata, strlen(cdata));
580 else if (!xmlStrcmp(type, BAD_CAST "numeric"))
582 (*term)->which = Z_Term_numeric;
583 (*term)->u.numeric = intVal(odr, cdata);
585 else if (!xmlStrcmp(type, BAD_CAST "string"))
587 (*term)->which = Z_Term_characterString;
588 (*term)->u.characterString = cdata;
590 else if (!xmlStrcmp(type, BAD_CAST "oid"))
593 *addinfo = "unhandled term type: oid";
595 else if (!xmlStrcmp(type, BAD_CAST "dateTime"))
598 *addinfo = "unhandled term type: dateTime";
600 else if (!xmlStrcmp(type, BAD_CAST "integerAndUnit"))
603 *addinfo = "unhandled term type: integerAndUnit";
605 else if (!xmlStrcmp(type, BAD_CAST "null"))
607 (*term)->which = Z_Term_null;
608 (*term)->u.null = odr_nullval();
613 *addinfo = "unhandled term type";
617 static void yaz_xml2query_apt(const xmlNode *ptr_apt,
618 Z_AttributesPlusTerm **zapt, ODR odr,
619 int *error_code, const char **addinfo)
621 const xmlNode *ptr = ptr_apt->children;
624 *zapt = (Z_AttributesPlusTerm *)
625 odr_malloc(odr, sizeof(Z_AttributesPlusTerm));
627 /* deal with attributes */
628 (*zapt)->attributes = (Z_AttributeList*)
629 odr_malloc(odr, sizeof(Z_AttributeList));
631 /* how many attributes? */
632 for (; ptr; ptr = ptr->next)
633 if (ptr->type == XML_ELEMENT_NODE)
635 if (!xmlStrcmp(ptr->name, BAD_CAST "attr"))
641 /* allocate and parse for real */
642 (*zapt)->attributes->num_attributes = num_attr;
643 (*zapt)->attributes->attributes = (Z_AttributeElement **)
644 odr_malloc(odr, sizeof(Z_AttributeElement*) * num_attr);
647 ptr = ptr_apt->children;
648 for (; ptr; ptr = ptr->next)
649 if (ptr->type == XML_ELEMENT_NODE)
651 if (!xmlStrcmp(ptr->name, BAD_CAST "attr"))
653 yaz_xml2query_attribute_element(
654 ptr, &(*zapt)->attributes->attributes[i], odr,
655 error_code, addinfo);
661 if (check_diagnostic(ptr, odr, error_code, addinfo))
664 if (ptr && ptr->type == XML_ELEMENT_NODE)
666 if (!xmlStrcmp(ptr->name, BAD_CAST "term"))
669 yaz_xml2query_term(ptr, &(*zapt)->term, odr, error_code, addinfo);
674 *addinfo = "bad element in apt content";
680 *addinfo = "missing term node in apt content";
684 static void yaz_xml2query_rset(const xmlNode *ptr, Z_ResultSetId **rset,
685 ODR odr, int *error_code, const char **addinfo)
689 *rset = strVal(ptr->children, odr);
694 *addinfo = "missing rset content";
698 static void yaz_xml2query_rpnstructure(const xmlNode *ptr, Z_RPNStructure **zs,
700 int *error_code, const char **addinfo)
702 while (ptr && ptr->type != XML_ELEMENT_NODE)
705 if (!ptr || ptr->type != XML_ELEMENT_NODE)
708 *addinfo = "missing rpn operator, rset, apt node";
711 if (check_diagnostic(ptr, odr, error_code, addinfo))
714 *zs = (Z_RPNStructure *) odr_malloc(odr, sizeof(Z_RPNStructure));
715 if (!xmlStrcmp(ptr->name, BAD_CAST "operator"))
717 Z_Complex *zc = (Z_Complex *) odr_malloc(odr, sizeof(Z_Complex));
719 (*zs)->which = Z_RPNStructure_complex;
720 (*zs)->u.complex = zc;
722 yaz_xml2query_operator(ptr, &zc->roperator, odr, error_code, addinfo);
725 while (ptr && ptr->type != XML_ELEMENT_NODE)
727 yaz_xml2query_rpnstructure(ptr, &zc->s1, odr, error_code, addinfo);
730 while (ptr && ptr->type != XML_ELEMENT_NODE)
732 yaz_xml2query_rpnstructure(ptr, &zc->s2, odr, error_code, addinfo);
736 Z_Operand *s = (Z_Operand *) odr_malloc(odr, sizeof(Z_Operand));
737 (*zs)->which = Z_RPNStructure_simple;
739 if (!xmlStrcmp(ptr->name, BAD_CAST "apt"))
741 s->which = Z_Operand_APT;
742 yaz_xml2query_apt(ptr, &s->u.attributesPlusTerm,
743 odr, error_code, addinfo);
745 else if (!xmlStrcmp(ptr->name, BAD_CAST "rset"))
747 s->which = Z_Operand_resultSetId;
748 yaz_xml2query_rset(ptr, &s->u.resultSetId,
749 odr, error_code, addinfo);
754 *addinfo = "bad element: expected binary, apt or rset";
759 static void yaz_xml2query_rpn(const xmlNode *ptr, Z_RPNQuery **query, ODR odr,
760 int *error_code, const char **addinfo)
762 const char *set = (const char *)
763 xmlGetProp((xmlNodePtr) ptr, BAD_CAST "set");
765 *query = (Z_RPNQuery*) odr_malloc(odr, sizeof(Z_RPNQuery));
767 (*query)->attributeSetId = yaz_string_to_oid_odr(yaz_oid_std(),
768 CLASS_ATTSET, set, odr);
770 (*query)->attributeSetId = 0;
771 yaz_xml2query_rpnstructure(ptr->children, &(*query)->RPNStructure,
772 odr, error_code, addinfo);
775 static void yaz_xml2query_(const xmlNode *ptr, Z_Query **query, ODR odr,
776 int *error_code, const char **addinfo)
778 if (check_diagnostic(ptr, odr, error_code, addinfo))
780 if (ptr && ptr->type == XML_ELEMENT_NODE &&
781 !xmlStrcmp(ptr->name, BAD_CAST "query"))
785 while (ptr && ptr->type != XML_ELEMENT_NODE)
787 if (!ptr || ptr->type != XML_ELEMENT_NODE)
790 *addinfo = "missing query content";
793 type = (const char *) ptr->name;
795 *query = (Z_Query*) odr_malloc(odr, sizeof(Z_Query));
796 if (!type || !strcmp(type, "rpn"))
798 (*query)->which = Z_Query_type_1;
799 yaz_xml2query_rpn(ptr, &(*query)->u.type_1, odr,
800 error_code, addinfo);
802 else if (!strcmp(type, "ccl"))
805 *addinfo = "ccl not supported yet";
807 else if (!strcmp(type, "z39.58"))
810 *addinfo = "z39.58 not supported yet";
812 else if (!strcmp(type, "cql"))
815 *addinfo = "cql not supported yet";
820 *addinfo = "unsupported query type";
826 *addinfo = "missing query element";
830 void yaz_xml2query(const xmlNode *xmlnodep, Z_Query **query, ODR odr,
831 int *error_code, const char **addinfo)
833 yaz_xml2query_(xmlnodep, query, odr, error_code, addinfo);
842 * c-file-style: "Stroustrup"
843 * indent-tabs-mode: nil
845 * vim: shiftwidth=4 tabstop=8 expandtab