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 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 xmlNodePtr yaz_query2xml_term(const Z_Term *term,
124 xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "term", 0);
126 const char *type = 0;
132 t = xmlNewTextLen(BAD_CAST term->u.general->buf, term->u.general->len);
136 sprintf(formstr, ODR_INT_PRINTF, *term->u.numeric);
137 t = xmlNewText(BAD_CAST formstr);
139 case Z_Term_characterString:
141 t = xmlNewText(BAD_CAST term->u.characterString);
146 case Z_Term_dateTime:
149 case Z_Term_external:
152 case Z_Term_integerAndUnit:
153 type ="integerAndUnit";
161 if (t) /* got a term node ? */
162 xmlAddChild(node, t);
164 xmlNewProp(node, BAD_CAST "type", BAD_CAST type);
168 xmlNodePtr yaz_query2xml_apt(const Z_AttributesPlusTerm *zapt,
171 xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "apt", 0);
172 int num_attributes = zapt->attributes->num_attributes;
174 for (i = 0; i<num_attributes; i++)
175 yaz_query2xml_attribute_element(zapt->attributes->attributes[i], node);
176 yaz_query2xml_term(zapt->term, node);
182 void yaz_query2xml_operator(Z_Operator *op, xmlNodePtr node)
184 const char *type = 0;
193 case Z_Operator_and_not:
196 case Z_Operator_prox:
202 xmlNewProp(node, BAD_CAST "type", BAD_CAST type);
204 if (op->which == Z_Operator_prox)
208 if (op->u.prox->exclusion)
210 if (*op->u.prox->exclusion)
211 xmlNewProp(node, BAD_CAST "exclusion", BAD_CAST "true");
213 xmlNewProp(node, BAD_CAST "exclusion", BAD_CAST "false");
215 sprintf(formstr, ODR_INT_PRINTF, *op->u.prox->distance);
216 xmlNewProp(node, BAD_CAST "distance", BAD_CAST formstr);
218 if (*op->u.prox->ordered)
219 xmlNewProp(node, BAD_CAST "ordered", BAD_CAST "true");
221 xmlNewProp(node, BAD_CAST "ordered", BAD_CAST "false");
223 sprintf(formstr, ODR_INT_PRINTF, *op->u.prox->relationType);
224 xmlNewProp(node, BAD_CAST "relationType", BAD_CAST formstr);
226 switch(op->u.prox->which)
228 case Z_ProximityOperator_known:
229 sprintf(formstr, ODR_INT_PRINTF, *op->u.prox->u.known);
230 xmlNewProp(node, BAD_CAST "knownProximityUnit",
233 case Z_ProximityOperator_private:
235 xmlNewProp(node, BAD_CAST "privateProximityUnit",
242 xmlNodePtr yaz_query2xml_rpnstructure(const Z_RPNStructure *zs,
245 if (zs->which == Z_RPNStructure_complex)
247 Z_Complex *zc = zs->u.complex;
249 xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "operator", 0);
251 yaz_query2xml_operator(zc->roperator, node);
252 yaz_query2xml_rpnstructure(zc->s1, node);
253 yaz_query2xml_rpnstructure(zc->s2, node);
256 else if (zs->which == Z_RPNStructure_simple)
258 if (zs->u.simple->which == Z_Operand_APT)
259 return yaz_query2xml_apt(zs->u.simple->u.attributesPlusTerm,
261 else if (zs->u.simple->which == Z_Operand_resultSetId)
262 return xmlNewChild(parent, /* NS */ 0, BAD_CAST "rset",
263 BAD_CAST zs->u.simple->u.resultSetId);
268 xmlNodePtr yaz_query2xml_rpn(const Z_RPNQuery *rpn, xmlNodePtr parent)
270 if (rpn->attributeSetId)
272 char oid_name_str[OID_STR_MAX];
273 const char *setname = yaz_oid_to_string_buf(rpn->attributeSetId,
276 xmlNewProp(parent, BAD_CAST "set", BAD_CAST setname);
278 return yaz_query2xml_rpnstructure(rpn->RPNStructure, parent);
281 xmlNodePtr yaz_query2xml_ccl(const Odr_oct *ccl, xmlNodePtr node)
286 xmlNodePtr yaz_query2xml_z3958(const Odr_oct *ccl, xmlNodePtr node)
291 xmlNodePtr yaz_query2xml_cql(const char *cql, xmlNodePtr node)
296 void yaz_rpnquery2xml(const Z_RPNQuery *rpn, xmlDocPtr *docp)
300 query.which = Z_Query_type_1;
301 query.u.type_1 = (Z_RPNQuery *) rpn;
302 yaz_query2xml(&query, docp);
305 void yaz_query2xml(const Z_Query *q, xmlDocPtr *docp)
307 xmlNodePtr top_node, q_node = 0, child_node = 0;
312 top_node = xmlNewNode(0, BAD_CAST "query");
317 case Z_Query_type_101:
318 q_node = xmlNewChild(top_node, 0, BAD_CAST "rpn", 0);
319 child_node = yaz_query2xml_rpn(q->u.type_1, q_node);
322 q_node = xmlNewChild(top_node, 0, BAD_CAST "ccl", 0);
323 child_node = yaz_query2xml_ccl(q->u.type_2, q_node);
325 case Z_Query_type_100:
326 q_node = xmlNewChild(top_node, 0, BAD_CAST "z39.58", 0);
327 child_node = yaz_query2xml_z3958(q->u.type_100, q_node);
329 case Z_Query_type_104:
330 if (q->u.type_104->which == Z_External_CQL)
332 q_node = xmlNewChild(top_node, 0, BAD_CAST "cql", 0);
333 child_node = yaz_query2xml_cql(q->u.type_104->u.cql, q_node);
336 if (child_node && q_node)
338 *docp = xmlNewDoc(BAD_CAST "1.0");
339 xmlDocSetRootElement(*docp, top_node); /* make it top node in doc */
344 xmlFreeNode(top_node);
348 bool_t *boolVal(ODR odr, const char *str)
350 if (*str == '\0' || strchr("0fF", *str))
351 return odr_booldup(odr, 0);
352 return odr_booldup(odr, 1);
355 Odr_int *intVal(ODR odr, const char *str)
357 return odr_intdup(odr, atoi(str));
360 void yaz_xml2query_operator(const xmlNode *ptr, Z_Operator **op,
361 ODR odr, 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 void yaz_xml2query_attribute_element(const xmlNode *ptr,
454 Z_AttributeElement **elem, ODR odr,
455 int *error_code, const char **addinfo)
462 struct _xmlAttr *attr;
463 for (attr = ptr->properties; attr; attr = attr->next)
465 if (!xmlStrcmp(attr->name, BAD_CAST "set") &&
466 attr->children && attr->children->type == XML_TEXT_NODE)
467 set = attr->children->content;
468 else if (!xmlStrcmp(attr->name, BAD_CAST "type") &&
469 attr->children && attr->children->type == XML_TEXT_NODE)
470 type = attr->children->content;
471 else if (!xmlStrcmp(attr->name, BAD_CAST "value") &&
472 attr->children && attr->children->type == XML_TEXT_NODE)
474 value = attr->children->content;
480 *addinfo = "bad attribute for attr content";
487 *addinfo = "missing type attribute for att content";
493 *addinfo = "missing value attribute for att content";
497 *elem = (Z_AttributeElement *) odr_malloc(odr, sizeof(**elem));
499 (*elem)->attributeSet = yaz_string_to_oid_odr(yaz_oid_std(),
504 (*elem)->attributeSet = 0;
505 (*elem)->attributeType = intVal(odr, (const char *) type);
507 /* looks like a number ? */
508 for (i = 0; value[i] && value[i] >= '0' && value[i] <= '9'; i++)
510 if (num_values > 1 || value[i])
511 { /* multiple values or string, so turn to complex attribute */
512 (*elem)->which = Z_AttributeValue_complex;
513 (*elem)->value.complex =
514 (Z_ComplexAttribute*) odr_malloc(odr, sizeof(Z_ComplexAttribute));
515 (*elem)->value.complex->num_list = num_values;
516 (*elem)->value.complex->list = (Z_StringOrNumeric **)
517 odr_malloc(odr, sizeof(Z_StringOrNumeric*) * num_values);
519 /* second pass over attr values */
521 for (attr = ptr->properties; attr; attr = attr->next)
523 if (!xmlStrcmp(attr->name, BAD_CAST "value") &&
524 attr->children && attr->children->type == XML_TEXT_NODE)
526 const char *val = (const char *) attr->children->content;
527 assert (i < num_values);
528 (*elem)->value.complex->list[i] = (Z_StringOrNumeric *)
529 odr_malloc(odr, sizeof(Z_StringOrNumeric));
530 (*elem)->value.complex->list[i]->which =
531 Z_StringOrNumeric_string;
532 (*elem)->value.complex->list[i]->u.string =
533 odr_strdup(odr, val);
537 (*elem)->value.complex->num_semanticAction = 0;
538 (*elem)->value.complex->semanticAction = 0;
541 { /* good'ld numeric value */
542 (*elem)->which = Z_AttributeValue_numeric;
543 (*elem)->value.numeric = intVal(odr, (const char *) value);
547 char *strVal(const xmlNode *ptr_cdata, ODR odr)
549 return nmem_text_node_cdata(ptr_cdata, odr_getmem(odr));
552 void yaz_xml2query_term(const xmlNode *ptr,
553 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 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 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 void yaz_xml2query_rpnstructure(const xmlNode *ptr, Z_RPNStructure **zs,
699 ODR odr, int *error_code, const char **addinfo)
701 while (ptr && ptr->type != XML_ELEMENT_NODE)
704 if (!ptr || ptr->type != XML_ELEMENT_NODE)
707 *addinfo = "missing rpn operator, rset, apt node";
710 if (check_diagnostic(ptr, odr, error_code, addinfo))
713 *zs = (Z_RPNStructure *) odr_malloc(odr, sizeof(Z_RPNStructure));
714 if (!xmlStrcmp(ptr->name, BAD_CAST "operator"))
716 Z_Complex *zc = (Z_Complex *) odr_malloc(odr, sizeof(Z_Complex));
718 (*zs)->which = Z_RPNStructure_complex;
719 (*zs)->u.complex = zc;
721 yaz_xml2query_operator(ptr, &zc->roperator, odr, error_code, addinfo);
724 while (ptr && ptr->type != XML_ELEMENT_NODE)
726 yaz_xml2query_rpnstructure(ptr, &zc->s1, odr, error_code, addinfo);
729 while (ptr && ptr->type != XML_ELEMENT_NODE)
731 yaz_xml2query_rpnstructure(ptr, &zc->s2, odr, error_code, addinfo);
735 Z_Operand *s = (Z_Operand *) odr_malloc(odr, sizeof(Z_Operand));
736 (*zs)->which = Z_RPNStructure_simple;
738 if (!xmlStrcmp(ptr->name, BAD_CAST "apt"))
740 s->which = Z_Operand_APT;
741 yaz_xml2query_apt(ptr, &s->u.attributesPlusTerm,
742 odr, error_code, addinfo);
744 else if (!xmlStrcmp(ptr->name, BAD_CAST "rset"))
746 s->which = Z_Operand_resultSetId;
747 yaz_xml2query_rset(ptr, &s->u.resultSetId,
748 odr, error_code, addinfo);
753 *addinfo = "bad element: expected binary, apt or rset";
758 void yaz_xml2query_rpn(const xmlNode *ptr, Z_RPNQuery **query, ODR odr,
759 int *error_code, const char **addinfo)
761 const char *set = (const char *)
762 xmlGetProp((xmlNodePtr) ptr, BAD_CAST "set");
764 *query = (Z_RPNQuery*) odr_malloc(odr, sizeof(Z_RPNQuery));
766 (*query)->attributeSetId = yaz_string_to_oid_odr(yaz_oid_std(),
767 CLASS_ATTSET, set, odr);
769 (*query)->attributeSetId = 0;
770 yaz_xml2query_rpnstructure(ptr->children, &(*query)->RPNStructure,
771 odr, error_code, addinfo);
774 static void yaz_xml2query_(const xmlNode *ptr, Z_Query **query, ODR odr,
775 int *error_code, const char **addinfo)
777 if (check_diagnostic(ptr, odr, error_code, addinfo))
779 if (ptr && ptr->type == XML_ELEMENT_NODE &&
780 !xmlStrcmp(ptr->name, BAD_CAST "query"))
784 while (ptr && ptr->type != XML_ELEMENT_NODE)
786 if (!ptr || ptr->type != XML_ELEMENT_NODE)
789 *addinfo = "missing query content";
792 type = (const char *) ptr->name;
794 *query = (Z_Query*) odr_malloc(odr, sizeof(Z_Query));
795 if (!type || !strcmp(type, "rpn"))
797 (*query)->which = Z_Query_type_1;
798 yaz_xml2query_rpn(ptr, &(*query)->u.type_1, odr,
799 error_code, addinfo);
801 else if (!strcmp(type, "ccl"))
804 *addinfo = "ccl not supported yet";
806 else if (!strcmp(type, "z39.58"))
809 *addinfo = "z39.58 not supported yet";
811 else if (!strcmp(type, "cql"))
814 *addinfo = "cql not supported yet";
819 *addinfo = "unsupported query type";
825 *addinfo = "missing query element";
829 void yaz_xml2query(const xmlNode *xmlnodep, Z_Query **query, ODR odr,
830 int *error_code, const char **addinfo)
832 yaz_xml2query_(xmlnodep, query, odr, error_code, addinfo);
841 * c-file-style: "Stroustrup"
842 * indent-tabs-mode: nil
844 * vim: shiftwidth=4 tabstop=8 expandtab