2 * Copyright (C) 1995-2007, Index Data ApS
5 * $Id: xmlquery.c,v 1.15 2007-05-06 20:12:20 adam Exp $
9 \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 void yaz_query2xml_attribute_element(const Z_AttributeElement *element,
29 const char *setname = 0;
30 char oid_name_str[OID_STR_MAX];
32 if (element->attributeSet)
34 setname = yaz_oid_to_string_buf(element->attributeSet,
38 if (element->which == Z_AttributeValue_numeric)
40 xmlNodePtr node = xmlNewChild(parent, 0, BAD_CAST "attr", 0);
43 xmlNewProp(node, BAD_CAST "set", BAD_CAST setname);
45 sprintf(formstr, "%d", *element->attributeType);
46 xmlNewProp(node, BAD_CAST "type", BAD_CAST formstr);
48 sprintf(formstr, "%d", *element->value.numeric);
49 xmlNewProp(node, BAD_CAST "value", BAD_CAST formstr);
51 else if (element->which == Z_AttributeValue_complex)
54 for (i = 0; i<element->value.complex->num_list; i++)
56 xmlNodePtr node = xmlNewChild(parent, 0, BAD_CAST "attr", 0);
59 xmlNewProp(node, BAD_CAST "set", BAD_CAST setname);
61 sprintf(formstr, "%d", *element->attributeType);
62 xmlNewProp(node, BAD_CAST "type", BAD_CAST formstr);
64 if (element->value.complex->list[i]->which ==
65 Z_StringOrNumeric_string)
67 xmlNewProp(node, BAD_CAST "value", BAD_CAST
68 element->value.complex->list[i]->u.string);
70 else if (element->value.complex->list[i]->which ==
71 Z_StringOrNumeric_numeric)
73 sprintf(formstr, "%d",
74 *element->value.complex->list[i]->u.numeric);
75 xmlNewProp(node, BAD_CAST "value", BAD_CAST formstr);
82 xmlNodePtr yaz_query2xml_term(const Z_Term *term,
86 xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "term", 0);
94 t = xmlNewTextLen(BAD_CAST term->u.general->buf, term->u.general->len);
98 sprintf(formstr, "%d", *term->u.numeric);
99 t = xmlNewText(BAD_CAST formstr);
101 case Z_Term_characterString:
103 t = xmlNewText(BAD_CAST term->u.characterString);
108 case Z_Term_dateTime:
111 case Z_Term_external:
114 case Z_Term_integerAndUnit:
115 type ="integerAndUnit";
123 if (t) /* got a term node ? */
124 xmlAddChild(node, t);
126 xmlNewProp(node, BAD_CAST "type", BAD_CAST type);
130 xmlNodePtr yaz_query2xml_apt(const Z_AttributesPlusTerm *zapt,
133 xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "apt", 0);
134 int num_attributes = zapt->attributes->num_attributes;
136 for (i = 0; i<num_attributes; i++)
137 yaz_query2xml_attribute_element(zapt->attributes->attributes[i], node);
138 yaz_query2xml_term(zapt->term, node);
144 void yaz_query2xml_operator(Z_Operator *op, xmlNodePtr node)
146 const char *type = 0;
155 case Z_Operator_and_not:
158 case Z_Operator_prox:
164 xmlNewProp(node, BAD_CAST "type", BAD_CAST type);
166 if (op->which == Z_Operator_prox)
170 if (op->u.prox->exclusion)
172 if (*op->u.prox->exclusion)
173 xmlNewProp(node, BAD_CAST "exclusion", BAD_CAST "true");
175 xmlNewProp(node, BAD_CAST "exclusion", BAD_CAST "false");
177 sprintf(formstr, "%d", *op->u.prox->distance);
178 xmlNewProp(node, BAD_CAST "distance", BAD_CAST formstr);
180 if (*op->u.prox->ordered)
181 xmlNewProp(node, BAD_CAST "ordered", BAD_CAST "true");
183 xmlNewProp(node, BAD_CAST "ordered", BAD_CAST "false");
185 sprintf(formstr, "%d", *op->u.prox->relationType);
186 xmlNewProp(node, BAD_CAST "relationType", BAD_CAST formstr);
188 switch(op->u.prox->which)
190 case Z_ProximityOperator_known:
191 sprintf(formstr, "%d", *op->u.prox->u.known);
192 xmlNewProp(node, BAD_CAST "knownProximityUnit",
195 case Z_ProximityOperator_private:
197 xmlNewProp(node, BAD_CAST "privateProximityUnit",
204 xmlNodePtr yaz_query2xml_rpnstructure(const Z_RPNStructure *zs,
207 if (zs->which == Z_RPNStructure_complex)
209 Z_Complex *zc = zs->u.complex;
211 xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "operator", 0);
213 yaz_query2xml_operator(zc->roperator, node);
214 yaz_query2xml_rpnstructure(zc->s1, node);
215 yaz_query2xml_rpnstructure(zc->s2, node);
218 else if (zs->which == Z_RPNStructure_simple)
220 if (zs->u.simple->which == Z_Operand_APT)
221 return yaz_query2xml_apt(zs->u.simple->u.attributesPlusTerm,
223 else if (zs->u.simple->which == Z_Operand_resultSetId)
224 return xmlNewChild(parent, /* NS */ 0, BAD_CAST "rset",
225 BAD_CAST zs->u.simple->u.resultSetId);
230 xmlNodePtr yaz_query2xml_rpn(const Z_RPNQuery *rpn, xmlNodePtr parent)
232 if (rpn->attributeSetId)
234 char oid_name_str[OID_STR_MAX];
235 const char *setname = yaz_oid_to_string_buf(rpn->attributeSetId,
238 xmlNewProp(parent, BAD_CAST "set", BAD_CAST setname);
240 return yaz_query2xml_rpnstructure(rpn->RPNStructure, parent);
243 xmlNodePtr yaz_query2xml_ccl(const Odr_oct *ccl, xmlNodePtr node)
248 xmlNodePtr yaz_query2xml_z3958(const Odr_oct *ccl, xmlNodePtr node)
253 xmlNodePtr yaz_query2xml_cql(const char *cql, xmlNodePtr node)
258 void yaz_rpnquery2xml(const Z_RPNQuery *rpn, xmlDocPtr *docp)
262 query.which = Z_Query_type_1;
263 query.u.type_1 = (Z_RPNQuery *) rpn;
264 yaz_query2xml(&query, docp);
267 void yaz_query2xml(const Z_Query *q, xmlDocPtr *docp)
269 xmlNodePtr top_node, q_node = 0, child_node = 0;
274 top_node = xmlNewNode(0, BAD_CAST "query");
279 case Z_Query_type_101:
280 q_node = xmlNewChild(top_node, 0, BAD_CAST "rpn", 0);
281 child_node = yaz_query2xml_rpn(q->u.type_1, q_node);
284 q_node = xmlNewChild(top_node, 0, BAD_CAST "ccl", 0);
285 child_node = yaz_query2xml_ccl(q->u.type_2, q_node);
287 case Z_Query_type_100:
288 q_node = xmlNewChild(top_node, 0, BAD_CAST "z39.58", 0);
289 child_node = yaz_query2xml_z3958(q->u.type_100, q_node);
291 case Z_Query_type_104:
292 if (q->u.type_104->which == Z_External_CQL)
294 q_node = xmlNewChild(top_node, 0, BAD_CAST "cql", 0);
295 child_node = yaz_query2xml_cql(q->u.type_104->u.cql, q_node);
298 if (child_node && q_node)
300 *docp = xmlNewDoc(BAD_CAST "1.0");
301 xmlDocSetRootElement(*docp, top_node); /* make it top node in doc */
306 xmlFreeNode(top_node);
310 bool_t *boolVal(ODR odr, const char *str)
312 if (*str == '\0' || strchr("0fF", *str))
313 return odr_intdup(odr, 0);
314 return odr_intdup(odr, 1);
317 int *intVal(ODR odr, const char *str)
319 return odr_intdup(odr, atoi(str));
322 void yaz_xml2query_operator(const xmlNode *ptr, Z_Operator **op,
323 ODR odr, int *error_code, const char **addinfo)
325 const char *type = (const char *)
326 xmlGetProp((xmlNodePtr) ptr, BAD_CAST "type");
330 *addinfo = "no operator type";
333 *op = (Z_Operator*) odr_malloc(odr, sizeof(Z_Operator));
334 if (!strcmp(type, "and"))
336 (*op)->which = Z_Operator_and;
337 (*op)->u.op_and = odr_nullval();
339 else if (!strcmp(type, "or"))
341 (*op)->which = Z_Operator_or;
342 (*op)->u.op_or = odr_nullval();
344 else if (!strcmp(type, "not"))
346 (*op)->which = Z_Operator_and_not;
347 (*op)->u.and_not = odr_nullval();
349 else if (!strcmp(type, "prox"))
352 Z_ProximityOperator *pop = (Z_ProximityOperator *)
353 odr_malloc(odr, sizeof(Z_ProximityOperator));
355 (*op)->which = Z_Operator_prox;
358 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
359 BAD_CAST "exclusion");
361 pop->exclusion = boolVal(odr, atval);
365 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
366 BAD_CAST "distance");
368 pop->distance = intVal(odr, atval);
370 pop->distance = odr_intdup(odr, 1);
372 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
375 pop->ordered = boolVal(odr, atval);
377 pop->ordered = odr_intdup(odr, 1);
379 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
380 BAD_CAST "relationType");
382 pop->relationType = intVal(odr, atval);
385 odr_intdup(odr, Z_ProximityOperator_Prox_lessThanOrEqual);
387 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
388 BAD_CAST "knownProximityUnit");
391 pop->which = Z_ProximityOperator_known;
392 pop->u.known = intVal(odr, atval);
396 pop->which = Z_ProximityOperator_known;
397 pop->u.known = odr_intdup(odr, Z_ProxUnit_word);
400 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
401 BAD_CAST "privateProximityUnit");
404 pop->which = Z_ProximityOperator_private;
405 pop->u.zprivate = intVal(odr, atval);
411 *addinfo = "bad operator type";
415 void yaz_xml2query_attribute_element(const xmlNode *ptr,
416 Z_AttributeElement **elem, ODR odr,
417 int *error_code, const char **addinfo)
424 struct _xmlAttr *attr;
425 for (attr = ptr->properties; attr; attr = attr->next)
427 if (!xmlStrcmp(attr->name, BAD_CAST "set") &&
428 attr->children && attr->children->type == XML_TEXT_NODE)
429 set = attr->children->content;
430 else if (!xmlStrcmp(attr->name, BAD_CAST "type") &&
431 attr->children && attr->children->type == XML_TEXT_NODE)
432 type = attr->children->content;
433 else if (!xmlStrcmp(attr->name, BAD_CAST "value") &&
434 attr->children && attr->children->type == XML_TEXT_NODE)
436 value = attr->children->content;
442 *addinfo = "bad attribute for attr content";
449 *addinfo = "missing type attribute for att content";
455 *addinfo = "missing value attribute for att content";
459 *elem = (Z_AttributeElement *) odr_malloc(odr, sizeof(**elem));
461 (*elem)->attributeSet = yaz_string_to_oid_odr(yaz_oid_std(),
466 (*elem)->attributeSet = 0;
467 (*elem)->attributeType = intVal(odr, (const char *) type);
469 /* looks like a number ? */
470 for (i = 0; value[i] && value[i] >= '0' && value[i] <= '9'; i++)
472 if (num_values > 1 || value[i])
473 { /* multiple values or string, so turn to complex attribute */
474 (*elem)->which = Z_AttributeValue_complex;
475 (*elem)->value.complex =
476 (Z_ComplexAttribute*) odr_malloc(odr, sizeof(Z_ComplexAttribute));
477 (*elem)->value.complex->num_list = num_values;
478 (*elem)->value.complex->list = (Z_StringOrNumeric **)
479 odr_malloc(odr, sizeof(Z_StringOrNumeric*) * num_values);
481 /* second pass over attr values */
483 for (attr = ptr->properties; attr; attr = attr->next)
485 if (!xmlStrcmp(attr->name, BAD_CAST "value") &&
486 attr->children && attr->children->type == XML_TEXT_NODE)
488 const char *val = (const char *) attr->children->content;
489 assert (i < num_values);
490 (*elem)->value.complex->list[i] = (Z_StringOrNumeric *)
491 odr_malloc(odr, sizeof(Z_StringOrNumeric));
492 (*elem)->value.complex->list[i]->which =
493 Z_StringOrNumeric_string;
494 (*elem)->value.complex->list[i]->u.string =
495 odr_strdup(odr, val);
499 (*elem)->value.complex->num_semanticAction = 0;
500 (*elem)->value.complex->semanticAction = 0;
503 { /* good'ld numeric value */
504 (*elem)->which = Z_AttributeValue_numeric;
505 (*elem)->value.numeric = intVal(odr, (const char *) value);
509 char *strVal(const xmlNode *ptr_cdata, ODR odr)
511 return nmem_text_node_cdata(ptr_cdata, odr_getmem(odr));
514 void yaz_xml2query_term(const xmlNode *ptr,
515 Z_Term **term, ODR odr,
516 int *error_code, const char **addinfo)
519 struct _xmlAttr *attr;
520 char *cdata = strVal(ptr->children, odr);
522 for (attr = ptr->properties; attr; attr = attr->next)
524 if (!xmlStrcmp(attr->name, BAD_CAST "type") &&
525 attr->children && attr->children->type == XML_TEXT_NODE)
526 type = attr->children->content;
530 *addinfo = "bad attribute for attr content";
534 *term = (Z_Term *) odr_malloc(odr, sizeof(Z_Term));
536 if (!type || !xmlStrcmp(type, BAD_CAST "general"))
538 (*term)->which = Z_Term_general;
540 odr_create_Odr_oct(odr, (unsigned char *)cdata, strlen(cdata));
542 else if (!xmlStrcmp(type, BAD_CAST "numeric"))
544 (*term)->which = Z_Term_numeric;
545 (*term)->u.numeric = intVal(odr, cdata);
547 else if (!xmlStrcmp(type, BAD_CAST "string"))
549 (*term)->which = Z_Term_characterString;
550 (*term)->u.characterString = cdata;
552 else if (!xmlStrcmp(type, BAD_CAST "oid"))
555 *addinfo = "unhandled term type: oid";
557 else if (!xmlStrcmp(type, BAD_CAST "dateTime"))
560 *addinfo = "unhandled term type: dateTime";
562 else if (!xmlStrcmp(type, BAD_CAST "integerAndUnit"))
565 *addinfo = "unhandled term type: integerAndUnit";
567 else if (!xmlStrcmp(type, BAD_CAST "null"))
569 (*term)->which = Z_Term_null;
570 (*term)->u.null = odr_nullval();
575 *addinfo = "unhandled term type";
579 void yaz_xml2query_apt(const xmlNode *ptr_apt,
580 Z_AttributesPlusTerm **zapt, ODR odr,
581 int *error_code, const char **addinfo)
583 const xmlNode *ptr = ptr_apt->children;
586 *zapt = (Z_AttributesPlusTerm *)
587 odr_malloc(odr, sizeof(Z_AttributesPlusTerm));
589 /* deal with attributes */
590 (*zapt)->attributes = (Z_AttributeList*)
591 odr_malloc(odr, sizeof(Z_AttributeList));
593 /* how many attributes? */
594 for (; ptr; ptr = ptr->next)
595 if (ptr->type == XML_ELEMENT_NODE)
597 if (!xmlStrcmp(ptr->name, BAD_CAST "attr"))
603 /* allocate and parse for real */
604 (*zapt)->attributes->num_attributes = num_attr;
605 (*zapt)->attributes->attributes = (Z_AttributeElement **)
606 odr_malloc(odr, sizeof(Z_AttributeElement*) * num_attr);
609 ptr = ptr_apt->children;
610 for (; ptr; ptr = ptr->next)
611 if (ptr->type == XML_ELEMENT_NODE)
613 if (!xmlStrcmp(ptr->name, BAD_CAST "attr"))
615 yaz_xml2query_attribute_element(
616 ptr, &(*zapt)->attributes->attributes[i], odr,
617 error_code, addinfo);
623 if (ptr && ptr->type == XML_ELEMENT_NODE)
625 if (!xmlStrcmp(ptr->name, BAD_CAST "term"))
628 yaz_xml2query_term(ptr, &(*zapt)->term, odr, error_code, addinfo);
633 *addinfo = "bad element in apt content";
639 *addinfo = "missing term node in apt content";
643 void yaz_xml2query_rset(const xmlNode *ptr, Z_ResultSetId **rset,
644 ODR odr, int *error_code, const char **addinfo)
648 *rset = strVal(ptr->children, odr);
653 *addinfo = "missing rset content";
657 void yaz_xml2query_rpnstructure(const xmlNode *ptr, Z_RPNStructure **zs,
658 ODR odr, int *error_code, const char **addinfo)
660 while (ptr && ptr->type != XML_ELEMENT_NODE)
663 if (!ptr || ptr->type != XML_ELEMENT_NODE)
666 *addinfo = "missing rpn operator, rset, apt node";
669 *zs = (Z_RPNStructure *) odr_malloc(odr, sizeof(Z_RPNStructure));
670 if (!xmlStrcmp(ptr->name, BAD_CAST "operator"))
672 Z_Complex *zc = (Z_Complex *) odr_malloc(odr, sizeof(Z_Complex));
674 (*zs)->which = Z_RPNStructure_complex;
675 (*zs)->u.complex = zc;
677 yaz_xml2query_operator(ptr, &zc->roperator, odr, error_code, addinfo);
680 while (ptr && ptr->type != XML_ELEMENT_NODE)
682 yaz_xml2query_rpnstructure(ptr, &zc->s1, odr, error_code, addinfo);
685 while (ptr && ptr->type != XML_ELEMENT_NODE)
687 yaz_xml2query_rpnstructure(ptr, &zc->s2, odr, error_code, addinfo);
691 Z_Operand *s = (Z_Operand *) odr_malloc(odr, sizeof(Z_Operand));
692 (*zs)->which = Z_RPNStructure_simple;
694 if (!xmlStrcmp(ptr->name, BAD_CAST "apt"))
696 s->which = Z_Operand_APT;
697 yaz_xml2query_apt(ptr, &s->u.attributesPlusTerm,
698 odr, error_code, addinfo);
700 else if (!xmlStrcmp(ptr->name, BAD_CAST "rset"))
702 s->which = Z_Operand_resultSetId;
703 yaz_xml2query_rset(ptr, &s->u.resultSetId,
704 odr, error_code, addinfo);
709 *addinfo = "bad element: expected binary, apt or rset";
714 void yaz_xml2query_rpn(const xmlNode *ptr, Z_RPNQuery **query, ODR odr,
715 int *error_code, const char **addinfo)
717 const char *set = (const char *)
718 xmlGetProp((xmlNodePtr) ptr, BAD_CAST "set");
720 *query = (Z_RPNQuery*) odr_malloc(odr, sizeof(Z_RPNQuery));
722 (*query)->attributeSetId = yaz_string_to_oid_odr(yaz_oid_std(),
723 CLASS_ATTSET, set, odr);
725 (*query)->attributeSetId = 0;
726 yaz_xml2query_rpnstructure(ptr->children, &(*query)->RPNStructure,
727 odr, error_code, addinfo);
730 static void yaz_xml2query_(const xmlNode *ptr, Z_Query **query, ODR odr,
731 int *error_code, const char **addinfo)
733 if (ptr && ptr->type == XML_ELEMENT_NODE &&
734 !xmlStrcmp(ptr->name, BAD_CAST "query"))
738 while (ptr && ptr->type != XML_ELEMENT_NODE)
740 if (!ptr || ptr->type != XML_ELEMENT_NODE)
743 *addinfo = "missing query content";
746 type = (const char *) ptr->name;
748 *query = (Z_Query*) odr_malloc(odr, sizeof(Z_Query));
749 if (!type || !strcmp(type, "rpn"))
751 (*query)->which = Z_Query_type_1;
752 yaz_xml2query_rpn(ptr, &(*query)->u.type_1, odr,
753 error_code, addinfo);
755 else if (!strcmp(type, "ccl"))
758 *addinfo = "ccl not supported yet";
760 else if (!strcmp(type, "z39.58"))
763 *addinfo = "z39.58 not supported yet";
765 else if (!strcmp(type, "cql"))
768 *addinfo = "cql not supported yet";
773 *addinfo = "unsupported query type";
779 *addinfo = "missing query element";
783 void yaz_xml2query(const xmlNode *xmlnodep, Z_Query **query, ODR odr,
784 int *error_code, const char **addinfo)
786 yaz_xml2query_(xmlnodep, query, odr, error_code, addinfo);
795 * indent-tabs-mode: nil
797 * vim: shiftwidth=4 tabstop=8 expandtab