1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2013 Index Data
3 * See the file LICENSE for details.
6 \brief Query / XML conversions
17 #include <libxml/parser.h>
18 #include <libxml/tree.h>
20 #include <yaz/logrpn.h>
21 #include <yaz/xmlquery.h>
22 #include <yaz/nmem_xml.h>
23 #include <yaz/oid_db.h>
25 static int check_diagnostic(const xmlNode *ptr, ODR odr,
26 int *error_code, const char **addinfo)
28 if (ptr && ptr->type == XML_ELEMENT_NODE &&
29 !xmlStrcmp(ptr->name, BAD_CAST "diagnostic"))
31 struct _xmlAttr *attr;
32 const char *code_str = 0;
33 const char *addinfo_str = 0;
34 for (attr = ptr->properties; attr; attr = attr->next)
36 if (!xmlStrcmp(attr->name, BAD_CAST "code") &&
37 attr->children && attr->children->type == XML_TEXT_NODE)
38 code_str = (const char *) attr->children->content;
39 else if (!xmlStrcmp(attr->name, BAD_CAST "addinfo") &&
40 attr->children && attr->children->type == XML_TEXT_NODE)
41 addinfo_str = (const char *) attr->children->content;
45 *addinfo = "bad attribute for diagnostic element";
52 *addinfo = "missing @code for diagnostic element";
55 *error_code = atoi(code_str);
57 *addinfo = odr_strdup(odr, addinfo_str);
64 static void yaz_query2xml_attribute_element(const Z_AttributeElement *element,
68 const char *setname = 0;
69 char oid_name_str[OID_STR_MAX];
71 if (element->attributeSet)
73 setname = yaz_oid_to_string_buf(element->attributeSet,
77 if (element->which == Z_AttributeValue_numeric)
79 xmlNodePtr node = xmlNewChild(parent, 0, BAD_CAST "attr", 0);
82 xmlNewProp(node, BAD_CAST "set", BAD_CAST setname);
84 assert(*element->attributeType > 0 && *element->attributeType < 20);
85 sprintf(formstr, ODR_INT_PRINTF, *element->attributeType);
86 xmlNewProp(node, BAD_CAST "type", BAD_CAST formstr);
88 sprintf(formstr, ODR_INT_PRINTF, *element->value.numeric);
89 xmlNewProp(node, BAD_CAST "value", BAD_CAST formstr);
91 else if (element->which == Z_AttributeValue_complex)
94 for (i = 0; i<element->value.complex->num_list; i++)
96 xmlNodePtr node = xmlNewChild(parent, 0, BAD_CAST "attr", 0);
99 xmlNewProp(node, BAD_CAST "set", BAD_CAST setname);
101 sprintf(formstr, ODR_INT_PRINTF, *element->attributeType);
102 xmlNewProp(node, BAD_CAST "type", BAD_CAST formstr);
104 if (element->value.complex->list[i]->which ==
105 Z_StringOrNumeric_string)
107 xmlNewProp(node, BAD_CAST "value", BAD_CAST
108 element->value.complex->list[i]->u.string);
110 else if (element->value.complex->list[i]->which ==
111 Z_StringOrNumeric_numeric)
113 sprintf(formstr, ODR_INT_PRINTF,
114 *element->value.complex->list[i]->u.numeric);
115 xmlNewProp(node, BAD_CAST "value", BAD_CAST formstr);
122 static xmlNodePtr yaz_query2xml_term(const Z_Term *term, xmlNodePtr parent)
125 xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "term", 0);
127 const char *type = 0;
133 t = xmlNewTextLen(BAD_CAST term->u.general->buf, term->u.general->len);
137 sprintf(formstr, ODR_INT_PRINTF, *term->u.numeric);
138 t = xmlNewText(BAD_CAST formstr);
140 case Z_Term_characterString:
142 t = xmlNewText(BAD_CAST term->u.characterString);
147 case Z_Term_dateTime:
150 case Z_Term_external:
153 case Z_Term_integerAndUnit:
154 type ="integerAndUnit";
162 if (t) /* got a term node ? */
163 xmlAddChild(node, t);
165 xmlNewProp(node, BAD_CAST "type", BAD_CAST type);
169 static xmlNodePtr yaz_query2xml_apt(const Z_AttributesPlusTerm *zapt,
172 xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "apt", 0);
173 int num_attributes = zapt->attributes->num_attributes;
175 for (i = 0; i<num_attributes; i++)
176 yaz_query2xml_attribute_element(zapt->attributes->attributes[i], node);
177 yaz_query2xml_term(zapt->term, node);
183 static void yaz_query2xml_operator(Z_Operator *op, xmlNodePtr node)
185 const char *type = 0;
194 case Z_Operator_and_not:
197 case Z_Operator_prox:
203 xmlNewProp(node, BAD_CAST "type", BAD_CAST type);
205 if (op->which == Z_Operator_prox)
209 if (op->u.prox->exclusion)
211 if (*op->u.prox->exclusion)
212 xmlNewProp(node, BAD_CAST "exclusion", BAD_CAST "true");
214 xmlNewProp(node, BAD_CAST "exclusion", BAD_CAST "false");
216 sprintf(formstr, ODR_INT_PRINTF, *op->u.prox->distance);
217 xmlNewProp(node, BAD_CAST "distance", BAD_CAST formstr);
219 if (*op->u.prox->ordered)
220 xmlNewProp(node, BAD_CAST "ordered", BAD_CAST "true");
222 xmlNewProp(node, BAD_CAST "ordered", BAD_CAST "false");
224 sprintf(formstr, ODR_INT_PRINTF, *op->u.prox->relationType);
225 xmlNewProp(node, BAD_CAST "relationType", BAD_CAST formstr);
227 switch(op->u.prox->which)
229 case Z_ProximityOperator_known:
230 sprintf(formstr, ODR_INT_PRINTF, *op->u.prox->u.known);
231 xmlNewProp(node, BAD_CAST "knownProximityUnit",
234 case Z_ProximityOperator_private:
236 xmlNewProp(node, BAD_CAST "privateProximityUnit",
243 static xmlNodePtr yaz_query2xml_rpnstructure(const Z_RPNStructure *zs,
246 if (zs->which == Z_RPNStructure_complex)
248 Z_Complex *zc = zs->u.complex;
250 xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "operator", 0);
252 yaz_query2xml_operator(zc->roperator, node);
253 yaz_query2xml_rpnstructure(zc->s1, node);
254 yaz_query2xml_rpnstructure(zc->s2, node);
257 else if (zs->which == Z_RPNStructure_simple)
259 if (zs->u.simple->which == Z_Operand_APT)
260 return yaz_query2xml_apt(zs->u.simple->u.attributesPlusTerm,
262 else if (zs->u.simple->which == Z_Operand_resultSetId)
263 return xmlNewChild(parent, /* NS */ 0, BAD_CAST "rset",
264 BAD_CAST zs->u.simple->u.resultSetId);
269 static xmlNodePtr yaz_query2xml_rpn(const Z_RPNQuery *rpn, xmlNodePtr parent)
271 if (rpn->attributeSetId)
273 char oid_name_str[OID_STR_MAX];
274 const char *setname = yaz_oid_to_string_buf(rpn->attributeSetId,
277 xmlNewProp(parent, BAD_CAST "set", BAD_CAST setname);
279 return yaz_query2xml_rpnstructure(rpn->RPNStructure, parent);
282 static xmlNodePtr yaz_query2xml_ccl(const Odr_oct *ccl, xmlNodePtr node)
287 static xmlNodePtr yaz_query2xml_z3958(const Odr_oct *ccl, xmlNodePtr node)
292 static xmlNodePtr yaz_query2xml_cql(const char *cql, xmlNodePtr node)
297 void yaz_rpnquery2xml(const Z_RPNQuery *rpn, xmlDocPtr *docp)
301 query.which = Z_Query_type_1;
302 query.u.type_1 = (Z_RPNQuery *) rpn;
303 yaz_query2xml(&query, docp);
306 void yaz_query2xml(const Z_Query *q, xmlDocPtr *docp)
308 xmlNodePtr top_node, q_node = 0, child_node = 0;
313 top_node = xmlNewNode(0, BAD_CAST "query");
318 case Z_Query_type_101:
319 q_node = xmlNewChild(top_node, 0, BAD_CAST "rpn", 0);
320 child_node = yaz_query2xml_rpn(q->u.type_1, q_node);
323 q_node = xmlNewChild(top_node, 0, BAD_CAST "ccl", 0);
324 child_node = yaz_query2xml_ccl(q->u.type_2, q_node);
326 case Z_Query_type_100:
327 q_node = xmlNewChild(top_node, 0, BAD_CAST "z39.58", 0);
328 child_node = yaz_query2xml_z3958(q->u.type_100, q_node);
330 case Z_Query_type_104:
331 if (q->u.type_104->which == Z_External_CQL)
333 q_node = xmlNewChild(top_node, 0, BAD_CAST "cql", 0);
334 child_node = yaz_query2xml_cql(q->u.type_104->u.cql, q_node);
337 if (child_node && q_node)
339 *docp = xmlNewDoc(BAD_CAST "1.0");
340 xmlDocSetRootElement(*docp, top_node); /* make it top node in doc */
345 xmlFreeNode(top_node);
349 static bool_t *boolVal(ODR odr, const char *str)
351 if (*str == '\0' || strchr("0fF", *str))
352 return odr_booldup(odr, 0);
353 return odr_booldup(odr, 1);
356 static Odr_int *intVal(ODR odr, const char *str)
358 return odr_intdup(odr, atoi(str));
361 static void yaz_xml2query_operator(const xmlNode *ptr, Z_Operator **op,
363 int *error_code, const char **addinfo)
365 xmlChar *type = xmlGetProp((xmlNodePtr) ptr, BAD_CAST "type");
369 *addinfo = "no operator type";
372 *op = (Z_Operator*) odr_malloc(odr, sizeof(Z_Operator));
373 if (!xmlStrcmp(type, BAD_CAST "and"))
375 (*op)->which = Z_Operator_and;
376 (*op)->u.op_and = odr_nullval();
378 else if (!xmlStrcmp(type, BAD_CAST "or"))
380 (*op)->which = Z_Operator_or;
381 (*op)->u.op_or = odr_nullval();
383 else if (!xmlStrcmp(type, BAD_CAST "not"))
385 (*op)->which = Z_Operator_and_not;
386 (*op)->u.and_not = odr_nullval();
388 else if (!xmlStrcmp(type, BAD_CAST "prox"))
390 struct _xmlAttr *attr;
391 Z_ProximityOperator *pop = (Z_ProximityOperator *)
392 odr_malloc(odr, sizeof(*pop));
393 (*op)->which = Z_Operator_prox;
397 pop->ordered = odr_booldup(odr, 1);
399 odr_intdup(odr, Z_ProximityOperator_Prox_lessThanOrEqual);
400 pop->which = Z_ProximityOperator_known;
401 pop->u.known = odr_intdup(odr, Z_ProxUnit_word);
402 pop->distance = odr_intdup(odr, 1);
404 for (attr = ptr->properties; attr; attr = attr->next)
406 const char *value = (const char *) attr->children->content;
407 if (!xmlStrcmp(attr->name, BAD_CAST "type"))
409 else if (!xmlStrcmp(attr->name, BAD_CAST "exclusion"))
410 pop->exclusion = boolVal(odr, value);
411 else if (!xmlStrcmp(attr->name, BAD_CAST "distance"))
412 pop->distance = intVal(odr, value);
413 else if (!xmlStrcmp(attr->name, BAD_CAST "ordered"))
414 pop->ordered = boolVal(odr, value);
415 else if (!xmlStrcmp(attr->name, BAD_CAST "relationType"))
416 pop->relationType = intVal(odr, value);
417 else if (!xmlStrcmp(attr->name, BAD_CAST "knownProximityUnit"))
419 pop->which = Z_ProximityOperator_known;
420 pop->u.known = intVal(odr, value);
422 else if (!xmlStrcmp(attr->name, BAD_CAST "privateProximityUnit"))
424 pop->which = Z_ProximityOperator_private;
425 pop->u.known = intVal(odr, value);
430 *addinfo = "bad proximity attribute";
438 *addinfo = "bad operator type";
443 static void yaz_xml2query_attribute_element(const xmlNode *ptr,
444 Z_AttributeElement **elem, ODR odr,
446 const char **addinfo)
453 struct _xmlAttr *attr;
454 for (attr = ptr->properties; attr; attr = attr->next)
456 if (!xmlStrcmp(attr->name, BAD_CAST "set") &&
457 attr->children && attr->children->type == XML_TEXT_NODE)
458 set = attr->children->content;
459 else if (!xmlStrcmp(attr->name, BAD_CAST "type") &&
460 attr->children && attr->children->type == XML_TEXT_NODE)
461 type = attr->children->content;
462 else if (!xmlStrcmp(attr->name, BAD_CAST "value") &&
463 attr->children && attr->children->type == XML_TEXT_NODE)
465 value = attr->children->content;
471 *addinfo = "bad attribute for attr content";
478 *addinfo = "missing type attribute for att content";
484 *addinfo = "missing value attribute for att content";
488 *elem = (Z_AttributeElement *) odr_malloc(odr, sizeof(**elem));
490 (*elem)->attributeSet = yaz_string_to_oid_odr(yaz_oid_std(),
495 (*elem)->attributeSet = 0;
496 (*elem)->attributeType = intVal(odr, (const char *) type);
498 /* looks like a number ? */
499 for (i = 0; value[i] && value[i] >= '0' && value[i] <= '9'; i++)
501 if (num_values > 1 || value[i])
502 { /* multiple values or string, so turn to complex attribute */
503 (*elem)->which = Z_AttributeValue_complex;
504 (*elem)->value.complex =
505 (Z_ComplexAttribute*) odr_malloc(odr, sizeof(Z_ComplexAttribute));
506 (*elem)->value.complex->num_list = num_values;
507 (*elem)->value.complex->list = (Z_StringOrNumeric **)
508 odr_malloc(odr, sizeof(Z_StringOrNumeric*) * num_values);
510 /* second pass over attr values */
512 for (attr = ptr->properties; attr; attr = attr->next)
514 if (!xmlStrcmp(attr->name, BAD_CAST "value") &&
515 attr->children && attr->children->type == XML_TEXT_NODE)
517 const char *val = (const char *) attr->children->content;
518 assert (i < num_values);
519 (*elem)->value.complex->list[i] = (Z_StringOrNumeric *)
520 odr_malloc(odr, sizeof(Z_StringOrNumeric));
521 (*elem)->value.complex->list[i]->which =
522 Z_StringOrNumeric_string;
523 (*elem)->value.complex->list[i]->u.string =
524 odr_strdup(odr, val);
528 (*elem)->value.complex->num_semanticAction = 0;
529 (*elem)->value.complex->semanticAction = 0;
532 { /* good'ld numeric value */
533 (*elem)->which = Z_AttributeValue_numeric;
534 (*elem)->value.numeric = intVal(odr, (const char *) value);
538 static char *strVal(const xmlNode *ptr_cdata, ODR odr)
540 return nmem_text_node_cdata(ptr_cdata, odr_getmem(odr));
543 static void yaz_xml2query_term(const xmlNode *ptr, Z_Term **term, ODR odr,
544 int *error_code, const char **addinfo)
547 struct _xmlAttr *attr;
548 char *cdata = strVal(ptr->children, odr);
550 for (attr = ptr->properties; attr; attr = attr->next)
552 if (!xmlStrcmp(attr->name, BAD_CAST "type") &&
553 attr->children && attr->children->type == XML_TEXT_NODE)
554 type = attr->children->content;
558 *addinfo = "bad attribute for attr content";
562 *term = (Z_Term *) odr_malloc(odr, sizeof(Z_Term));
564 if (!type || !xmlStrcmp(type, BAD_CAST "general"))
566 (*term)->which = Z_Term_general;
568 odr_create_Odr_oct(odr, cdata, strlen(cdata));
570 else if (!xmlStrcmp(type, BAD_CAST "numeric"))
572 (*term)->which = Z_Term_numeric;
573 (*term)->u.numeric = intVal(odr, cdata);
575 else if (!xmlStrcmp(type, BAD_CAST "string"))
577 (*term)->which = Z_Term_characterString;
578 (*term)->u.characterString = cdata;
580 else if (!xmlStrcmp(type, BAD_CAST "oid"))
583 *addinfo = "unhandled term type: oid";
585 else if (!xmlStrcmp(type, BAD_CAST "dateTime"))
588 *addinfo = "unhandled term type: dateTime";
590 else if (!xmlStrcmp(type, BAD_CAST "integerAndUnit"))
593 *addinfo = "unhandled term type: integerAndUnit";
595 else if (!xmlStrcmp(type, BAD_CAST "null"))
597 (*term)->which = Z_Term_null;
598 (*term)->u.null = odr_nullval();
603 *addinfo = "unhandled term type";
607 static void yaz_xml2query_apt(const xmlNode *ptr_apt,
608 Z_AttributesPlusTerm **zapt, ODR odr,
609 int *error_code, const char **addinfo)
611 const xmlNode *ptr = ptr_apt->children;
614 *zapt = (Z_AttributesPlusTerm *)
615 odr_malloc(odr, sizeof(Z_AttributesPlusTerm));
617 /* deal with attributes */
618 (*zapt)->attributes = (Z_AttributeList*)
619 odr_malloc(odr, sizeof(Z_AttributeList));
621 /* how many attributes? */
622 for (; ptr; ptr = ptr->next)
623 if (ptr->type == XML_ELEMENT_NODE)
625 if (!xmlStrcmp(ptr->name, BAD_CAST "attr"))
631 /* allocate and parse for real */
632 (*zapt)->attributes->num_attributes = num_attr;
633 (*zapt)->attributes->attributes = (Z_AttributeElement **)
634 odr_malloc(odr, sizeof(Z_AttributeElement*) * num_attr);
637 ptr = ptr_apt->children;
638 for (; ptr; ptr = ptr->next)
639 if (ptr->type == XML_ELEMENT_NODE)
641 if (!xmlStrcmp(ptr->name, BAD_CAST "attr"))
643 yaz_xml2query_attribute_element(
644 ptr, &(*zapt)->attributes->attributes[i], odr,
645 error_code, addinfo);
651 if (check_diagnostic(ptr, odr, error_code, addinfo))
654 if (ptr && ptr->type == XML_ELEMENT_NODE)
656 if (!xmlStrcmp(ptr->name, BAD_CAST "term"))
659 yaz_xml2query_term(ptr, &(*zapt)->term, odr, error_code, addinfo);
664 *addinfo = "bad element in apt content";
670 *addinfo = "missing term node in apt content";
674 static void yaz_xml2query_rset(const xmlNode *ptr, Z_ResultSetId **rset,
675 ODR odr, int *error_code, const char **addinfo)
679 *rset = strVal(ptr->children, odr);
684 *addinfo = "missing rset content";
688 static void yaz_xml2query_rpnstructure(const xmlNode *ptr, Z_RPNStructure **zs,
690 int *error_code, const char **addinfo)
692 while (ptr && ptr->type != XML_ELEMENT_NODE)
695 if (!ptr || ptr->type != XML_ELEMENT_NODE)
698 *addinfo = "missing rpn operator, rset, apt node";
701 if (check_diagnostic(ptr, odr, error_code, addinfo))
704 *zs = (Z_RPNStructure *) odr_malloc(odr, sizeof(Z_RPNStructure));
705 if (!xmlStrcmp(ptr->name, BAD_CAST "operator"))
707 Z_Complex *zc = (Z_Complex *) odr_malloc(odr, sizeof(Z_Complex));
709 (*zs)->which = Z_RPNStructure_complex;
710 (*zs)->u.complex = zc;
712 yaz_xml2query_operator(ptr, &zc->roperator, odr, error_code, addinfo);
715 while (ptr && ptr->type != XML_ELEMENT_NODE)
717 yaz_xml2query_rpnstructure(ptr, &zc->s1, odr, error_code, addinfo);
720 while (ptr && ptr->type != XML_ELEMENT_NODE)
722 yaz_xml2query_rpnstructure(ptr, &zc->s2, odr, error_code, addinfo);
726 Z_Operand *s = (Z_Operand *) odr_malloc(odr, sizeof(Z_Operand));
727 (*zs)->which = Z_RPNStructure_simple;
729 if (!xmlStrcmp(ptr->name, BAD_CAST "apt"))
731 s->which = Z_Operand_APT;
732 yaz_xml2query_apt(ptr, &s->u.attributesPlusTerm,
733 odr, error_code, addinfo);
735 else if (!xmlStrcmp(ptr->name, BAD_CAST "rset"))
737 s->which = Z_Operand_resultSetId;
738 yaz_xml2query_rset(ptr, &s->u.resultSetId,
739 odr, error_code, addinfo);
744 *addinfo = "bad element: expected binary, apt or rset";
749 static void yaz_xml2query_rpn(const xmlNode *ptr, Z_RPNQuery **query, ODR odr,
750 int *error_code, const char **addinfo)
752 xmlChar *set = xmlGetProp((xmlNodePtr) ptr, BAD_CAST "set");
754 *query = (Z_RPNQuery*) odr_malloc(odr, sizeof(Z_RPNQuery));
757 (*query)->attributeSetId =
758 yaz_string_to_oid_odr(yaz_oid_std(),
759 CLASS_ATTSET, (const char *) set, odr);
763 (*query)->attributeSetId = 0;
764 yaz_xml2query_rpnstructure(ptr->children, &(*query)->RPNStructure,
765 odr, error_code, addinfo);
768 static void yaz_xml2query_(const xmlNode *ptr, Z_Query **query, ODR odr,
769 int *error_code, const char **addinfo)
771 if (check_diagnostic(ptr, odr, error_code, addinfo))
773 if (ptr && ptr->type == XML_ELEMENT_NODE &&
774 !xmlStrcmp(ptr->name, BAD_CAST "query"))
778 while (ptr && ptr->type != XML_ELEMENT_NODE)
780 if (!ptr || ptr->type != XML_ELEMENT_NODE)
783 *addinfo = "missing query content";
786 type = (const char *) ptr->name;
788 *query = (Z_Query*) odr_malloc(odr, sizeof(Z_Query));
789 if (!type || !strcmp(type, "rpn"))
791 (*query)->which = Z_Query_type_1;
792 yaz_xml2query_rpn(ptr, &(*query)->u.type_1, odr,
793 error_code, addinfo);
795 else if (!strcmp(type, "ccl"))
798 *addinfo = "ccl not supported yet";
800 else if (!strcmp(type, "z39.58"))
803 *addinfo = "z39.58 not supported yet";
805 else if (!strcmp(type, "cql"))
808 *addinfo = "cql not supported yet";
813 *addinfo = "unsupported query type";
819 *addinfo = "missing query element";
823 void yaz_xml2query(const xmlNode *xmlnodep, Z_Query **query, ODR odr,
824 int *error_code, const char **addinfo)
826 yaz_xml2query_(xmlnodep, query, odr, error_code, addinfo);
835 * c-file-style: "Stroustrup"
836 * indent-tabs-mode: nil
838 * vim: shiftwidth=4 tabstop=8 expandtab