2 * Copyright (C) 1995-2005, Index Data ApS
5 * $Id: xmlquery.c,v 1.6 2006-02-23 13:09:54 adam Exp $
10 * \brief Query / XML conversions
18 #include <libxml/parser.h>
19 #include <libxml/tree.h>
21 #include <yaz/logrpn.h>
22 #include <yaz/xmlquery.h>
24 void yaz_query2xml_attribute_element(const Z_AttributeElement *element,
28 const char *setname = 0;
30 if (element->attributeSet)
33 attrset = oid_getentbyoid (element->attributeSet);
34 setname = attrset->desc;
37 if (element->which == Z_AttributeValue_numeric)
39 xmlNodePtr node = xmlNewChild(parent, 0, BAD_CAST "attr", 0);
42 xmlNewProp(node, BAD_CAST "set", BAD_CAST setname);
44 sprintf(formstr, "%d", *element->attributeType);
45 xmlNewProp(node, BAD_CAST "type", BAD_CAST formstr);
47 sprintf(formstr, "%d", *element->value.numeric);
48 xmlNewProp(node, BAD_CAST "value", BAD_CAST formstr);
50 else if (element->which == Z_AttributeValue_complex)
53 for (i = 0; i<element->value.complex->num_list; i++)
55 xmlNodePtr node = xmlNewChild(parent, 0, BAD_CAST "attr", 0);
58 xmlNewProp(node, BAD_CAST "set", BAD_CAST setname);
60 sprintf(formstr, "%d", *element->attributeType);
61 xmlNewProp(node, BAD_CAST "type", BAD_CAST formstr);
63 if (element->value.complex->list[i]->which ==
64 Z_StringOrNumeric_string)
66 xmlNewProp(node, BAD_CAST "value", BAD_CAST
67 element->value.complex->list[i]->u.string);
69 else if (element->value.complex->list[i]->which ==
70 Z_StringOrNumeric_numeric)
72 sprintf(formstr, "%d",
73 *element->value.complex->list[i]->u.numeric);
74 xmlNewProp(node, BAD_CAST "value", BAD_CAST formstr);
81 xmlNodePtr yaz_query2xml_term(const Z_Term *term,
85 xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "term", 0);
93 t = xmlNewTextLen(BAD_CAST term->u.general->buf, term->u.general->len);
97 sprintf(formstr, "%d", *term->u.numeric);
98 t = xmlNewText(BAD_CAST formstr);
100 case Z_Term_characterString:
102 t = xmlNewText(BAD_CAST term->u.characterString);
107 case Z_Term_dateTime:
110 case Z_Term_external:
113 case Z_Term_integerAndUnit:
114 type ="integerAndUnit";
122 if (t) /* got a term node ? */
123 xmlAddChild(node, t);
125 xmlNewProp(node, BAD_CAST "type", BAD_CAST type);
129 xmlNodePtr yaz_query2xml_apt(const Z_AttributesPlusTerm *zapt,
132 xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "apt", 0);
133 int num_attributes = zapt->attributes->num_attributes;
135 for (i = 0; i<num_attributes; i++)
136 yaz_query2xml_attribute_element(zapt->attributes->attributes[i], node);
137 yaz_query2xml_term(zapt->term, node);
143 void yaz_query2xml_operator(Z_Operator *op, xmlNodePtr node)
145 const char *type = 0;
154 case Z_Operator_and_not:
157 case Z_Operator_prox:
163 xmlNewProp(node, BAD_CAST "type", BAD_CAST type);
165 if (op->which == Z_Operator_prox)
169 if (op->u.prox->exclusion)
171 if (*op->u.prox->exclusion)
172 xmlNewProp(node, BAD_CAST "exclusion", BAD_CAST "true");
174 xmlNewProp(node, BAD_CAST "exclusion", BAD_CAST "false");
176 sprintf(formstr, "%d", *op->u.prox->distance);
177 xmlNewProp(node, BAD_CAST "distance", BAD_CAST formstr);
179 if (*op->u.prox->ordered)
180 xmlNewProp(node, BAD_CAST "ordered", BAD_CAST "true");
182 xmlNewProp(node, BAD_CAST "ordered", BAD_CAST "false");
184 sprintf(formstr, "%d", *op->u.prox->relationType);
185 xmlNewProp(node, BAD_CAST "relationType", BAD_CAST formstr);
187 switch(op->u.prox->which)
189 case Z_ProximityOperator_known:
190 sprintf(formstr, "%d", *op->u.prox->u.known);
191 xmlNewProp(node, BAD_CAST "knownProximityUnit",
194 case Z_ProximityOperator_private:
196 xmlNewProp(node, BAD_CAST "privateProximityUnit",
203 xmlNodePtr yaz_query2xml_rpnstructure(const Z_RPNStructure *zs,
206 if (zs->which == Z_RPNStructure_complex)
208 Z_Complex *zc = zs->u.complex;
210 xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "operator", 0);
212 yaz_query2xml_operator(zc->roperator, node);
213 yaz_query2xml_rpnstructure(zc->s1, node);
214 yaz_query2xml_rpnstructure(zc->s2, node);
217 else if (zs->which == Z_RPNStructure_simple)
219 if (zs->u.simple->which == Z_Operand_APT)
220 return yaz_query2xml_apt(zs->u.simple->u.attributesPlusTerm,
222 else if (zs->u.simple->which == Z_Operand_resultSetId)
223 return xmlNewChild(parent, /* NS */ 0, BAD_CAST "rset",
224 BAD_CAST zs->u.simple->u.resultSetId);
229 xmlNodePtr yaz_query2xml_rpn(const Z_RPNQuery *rpn, xmlNodePtr parent)
231 oident *attrset = oid_getentbyoid (rpn->attributeSetId);
232 if (attrset && attrset->value)
233 xmlNewProp(parent, BAD_CAST "set", BAD_CAST attrset->desc);
234 return yaz_query2xml_rpnstructure(rpn->RPNStructure, parent);
237 xmlNodePtr yaz_query2xml_ccl(const Odr_oct *ccl, xmlNodePtr node)
242 xmlNodePtr yaz_query2xml_z3958(const Odr_oct *ccl, xmlNodePtr node)
247 xmlNodePtr yaz_query2xml_cql(const char *cql, xmlNodePtr node)
252 void yaz_rpnquery2xml(const Z_RPNQuery *rpn, void *docp_void)
256 query.which = Z_Query_type_1;
257 query.u.type_1 = (Z_RPNQuery *) rpn;
258 yaz_query2xml(&query, docp_void);
261 void yaz_query2xml(const Z_Query *q, void *docp_void)
263 xmlDocPtr *docp = (xmlDocPtr *) docp_void;
264 xmlNodePtr top_node, q_node = 0, child_node = 0;
269 top_node = xmlNewNode(0, BAD_CAST "query");
274 case Z_Query_type_101:
275 q_node = xmlNewChild(top_node, 0, BAD_CAST "rpn", 0);
276 child_node = yaz_query2xml_rpn(q->u.type_1, q_node);
279 q_node = xmlNewChild(top_node, 0, BAD_CAST "ccl", 0);
280 child_node = yaz_query2xml_ccl(q->u.type_2, q_node);
282 case Z_Query_type_100:
283 q_node = xmlNewChild(top_node, 0, BAD_CAST "z39.58", 0);
284 child_node = yaz_query2xml_z3958(q->u.type_100, q_node);
286 case Z_Query_type_104:
287 if (q->u.type_104->which == Z_External_CQL)
289 q_node = xmlNewChild(top_node, 0, BAD_CAST "cql", 0);
290 child_node = yaz_query2xml_cql(q->u.type_104->u.cql, q_node);
293 if (child_node && q_node)
295 *docp = xmlNewDoc(BAD_CAST "1.0");
296 xmlDocSetRootElement(*docp, top_node); /* make it top node in doc */
301 xmlFreeNode(top_node);
305 bool_t *boolVal(ODR odr, const char *str)
307 if (*str == '\0' || strchr("0fF", *str))
308 return odr_intdup(odr, 0);
309 return odr_intdup(odr, 1);
312 int *intVal(ODR odr, const char *str)
314 return odr_intdup(odr, atoi(str));
317 void yaz_xml2query_operator(const xmlNode *ptr, Z_Operator **op,
318 ODR odr, int *error_code, const char **addinfo)
320 const char *type = (const char *)
321 xmlGetProp((xmlNodePtr) ptr, BAD_CAST "type");
325 *addinfo = "no operator type";
328 *op = (Z_Operator*) odr_malloc(odr, sizeof(Z_Operator));
329 if (!strcmp(type, "and"))
331 (*op)->which = Z_Operator_and;
332 (*op)->u.op_and = odr_nullval();
334 else if (!strcmp(type, "or"))
336 (*op)->which = Z_Operator_or;
337 (*op)->u.op_or = odr_nullval();
339 else if (!strcmp(type, "not"))
341 (*op)->which = Z_Operator_and_not;
342 (*op)->u.and_not = odr_nullval();
344 else if (!strcmp(type, "prox"))
347 Z_ProximityOperator *pop = (Z_ProximityOperator *)
348 odr_malloc(odr, sizeof(Z_ProximityOperator));
350 (*op)->which = Z_Operator_prox;
353 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
354 BAD_CAST "exclusion");
356 pop->exclusion = boolVal(odr, atval);
360 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
361 BAD_CAST "distance");
363 pop->distance = intVal(odr, atval);
365 pop->distance = odr_intdup(odr, 1);
367 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
370 pop->ordered = boolVal(odr, atval);
372 pop->ordered = odr_intdup(odr, 1);
374 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
375 BAD_CAST "relationType");
377 pop->relationType = intVal(odr, atval);
380 odr_intdup(odr, Z_ProximityOperator_Prox_lessThanOrEqual);
382 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
383 BAD_CAST "knownProximityUnit");
386 pop->which = Z_ProximityOperator_known;
387 pop->u.known = intVal(odr, atval);
391 pop->which = Z_ProximityOperator_known;
392 pop->u.known = odr_intdup(odr, Z_ProxUnit_word);
395 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
396 BAD_CAST "privateProximityUnit");
399 pop->which = Z_ProximityOperator_private;
400 pop->u.zprivate = intVal(odr, atval);
406 *addinfo = "bad operator type";
410 void yaz_xml2query_attribute_element(const xmlNode *ptr,
411 Z_AttributeElement **elem, ODR odr,
412 int *error_code, const char **addinfo)
419 struct _xmlAttr *attr;
420 for (attr = ptr->properties; attr; attr = attr->next)
422 if (!xmlStrcmp(attr->name, BAD_CAST "set") &&
423 attr->children && attr->children->type == XML_TEXT_NODE)
424 set = attr->children->content;
425 else if (!xmlStrcmp(attr->name, BAD_CAST "type") &&
426 attr->children && attr->children->type == XML_TEXT_NODE)
427 type = attr->children->content;
428 else if (!xmlStrcmp(attr->name, BAD_CAST "value") &&
429 attr->children && attr->children->type == XML_TEXT_NODE)
431 value = attr->children->content;
437 *addinfo = "bad attribute for attr content";
444 *addinfo = "missing type attribute for att content";
450 *addinfo = "missing value attribute for att content";
454 *elem = (Z_AttributeElement *) odr_malloc(odr, sizeof(**elem));
456 (*elem)->attributeSet = yaz_str_to_z3950oid(odr, CLASS_ATTSET,
459 (*elem)->attributeSet = 0;
460 (*elem)->attributeType = intVal(odr, (const char *) type);
462 /* looks like a number ? */
463 for (i = 0; value[i] && value[i] >= '0' && value[i] <= '9'; i++)
465 if (num_values > 1 || value[i])
466 { /* multiple values or string, so turn to complex attribute */
467 (*elem)->which = Z_AttributeValue_complex;
468 (*elem)->value.complex =
469 (Z_ComplexAttribute*) odr_malloc(odr, sizeof(Z_ComplexAttribute));
470 (*elem)->value.complex->num_list = num_values;
471 (*elem)->value.complex->list = (Z_StringOrNumeric **)
472 odr_malloc(odr, sizeof(Z_StringOrNumeric*) * num_values);
474 /* second pass over attr values */
476 for (attr = ptr->properties; attr; attr = attr->next)
478 if (!xmlStrcmp(attr->name, BAD_CAST "value") &&
479 attr->children && attr->children->type == XML_TEXT_NODE)
481 const char *val = (const char *) attr->children->content;
482 assert (i < num_values);
483 (*elem)->value.complex->list[i] = (Z_StringOrNumeric *)
484 odr_malloc(odr, sizeof(Z_StringOrNumeric));
485 (*elem)->value.complex->list[i]->which =
486 Z_StringOrNumeric_string;
487 (*elem)->value.complex->list[i]->u.string =
488 odr_strdup(odr, val);
492 (*elem)->value.complex->num_semanticAction = 0;
493 (*elem)->value.complex->semanticAction = 0;
496 { /* good'ld numeric value */
497 (*elem)->which = Z_AttributeValue_numeric;
498 (*elem)->value.numeric = intVal(odr, (const char *) value);
502 char *strVal(const xmlNode *ptr_cdata, ODR odr)
508 for (ptr = ptr_cdata; ptr; ptr = ptr->next)
509 if (ptr->type == XML_TEXT_NODE)
510 len += xmlStrlen(ptr->content);
511 cdata = (char *) odr_malloc(odr, len+1);
513 for (ptr = ptr_cdata; ptr; ptr = ptr->next)
514 if (ptr->type == XML_TEXT_NODE)
515 strcat(cdata, (const char *) ptr->content);
519 void yaz_xml2query_term(const xmlNode *ptr,
520 Z_Term **term, ODR odr,
521 int *error_code, const char **addinfo)
524 struct _xmlAttr *attr;
525 char *cdata = strVal(ptr->children, odr);
527 for (attr = ptr->properties; attr; attr = attr->next)
529 if (!xmlStrcmp(attr->name, BAD_CAST "type") &&
530 attr->children && attr->children->type == XML_TEXT_NODE)
531 type = attr->children->content;
535 *addinfo = "bad attribute for attr content";
539 *term = (Z_Term *) odr_malloc(odr, sizeof(Z_Term));
541 if (!type || !xmlStrcmp(type, BAD_CAST "general"))
543 (*term)->which = Z_Term_general;
545 odr_create_Odr_oct(odr, (unsigned char *)cdata, strlen(cdata));
547 else if (!xmlStrcmp(type, BAD_CAST "numeric"))
549 (*term)->which = Z_Term_numeric;
550 (*term)->u.numeric = intVal(odr, cdata);
552 else if (!xmlStrcmp(type, BAD_CAST "string"))
554 (*term)->which = Z_Term_characterString;
555 (*term)->u.characterString = cdata;
557 else if (!xmlStrcmp(type, BAD_CAST "oid"))
560 *addinfo = "unhandled term type: oid";
562 else if (!xmlStrcmp(type, BAD_CAST "dateTime"))
565 *addinfo = "unhandled term type: dateTime";
567 else if (!xmlStrcmp(type, BAD_CAST "integerAndUnit"))
570 *addinfo = "unhandled term type: integerAndUnit";
572 else if (!xmlStrcmp(type, BAD_CAST "null"))
574 (*term)->which = Z_Term_null;
575 (*term)->u.null = odr_nullval();
580 *addinfo = "unhandled term type";
584 void yaz_xml2query_apt(const xmlNode *ptr_apt,
585 Z_AttributesPlusTerm **zapt, ODR odr,
586 int *error_code, const char **addinfo)
588 const xmlNode *ptr = ptr_apt->children;
591 *zapt = (Z_AttributesPlusTerm *)
592 odr_malloc(odr, sizeof(Z_AttributesPlusTerm));
594 /* deal with attributes */
595 (*zapt)->attributes = (Z_AttributeList*)
596 odr_malloc(odr, sizeof(Z_AttributeList));
598 /* how many attributes? */
599 for (; ptr; ptr = ptr->next)
600 if (ptr->type == XML_ELEMENT_NODE)
602 if (!xmlStrcmp(ptr->name, BAD_CAST "attr"))
608 /* allocate and parse for real */
609 (*zapt)->attributes->num_attributes = num_attr;
610 (*zapt)->attributes->attributes = (Z_AttributeElement **)
611 odr_malloc(odr, sizeof(Z_AttributeElement*) * num_attr);
614 ptr = ptr_apt->children;
615 for (; ptr; ptr = ptr->next)
616 if (ptr->type == XML_ELEMENT_NODE)
618 if (!xmlStrcmp(ptr->name, BAD_CAST "attr"))
620 yaz_xml2query_attribute_element(
621 ptr, &(*zapt)->attributes->attributes[i], odr,
622 error_code, addinfo);
628 if (ptr && ptr->type == XML_ELEMENT_NODE)
630 if (!xmlStrcmp(ptr->name, BAD_CAST "term"))
633 yaz_xml2query_term(ptr, &(*zapt)->term, odr, error_code, addinfo);
638 *addinfo = "bad element in apt content";
644 *addinfo = "missing term node in apt content";
648 void yaz_xml2query_rset(const xmlNode *ptr, Z_ResultSetId **rset,
649 ODR odr, int *error_code, const char **addinfo)
653 *rset = strVal(ptr->children, odr);
658 *addinfo = "missing rset content";
662 void yaz_xml2query_rpnstructure(const xmlNode *ptr, Z_RPNStructure **zs,
663 ODR odr, int *error_code, const char **addinfo)
665 while (ptr && ptr->type != XML_ELEMENT_NODE)
668 if (!ptr || ptr->type != XML_ELEMENT_NODE)
671 *addinfo = "missing rpn operator, rset, apt node";
674 *zs = (Z_RPNStructure *) odr_malloc(odr, sizeof(Z_RPNStructure));
675 if (!xmlStrcmp(ptr->name, BAD_CAST "operator"))
677 Z_Complex *zc = odr_malloc(odr, sizeof(Z_Complex));
679 (*zs)->which = Z_RPNStructure_complex;
680 (*zs)->u.complex = zc;
682 yaz_xml2query_operator(ptr, &zc->roperator, odr, error_code, addinfo);
685 while (ptr && ptr->type != XML_ELEMENT_NODE)
687 yaz_xml2query_rpnstructure(ptr, &zc->s1, odr, error_code, addinfo);
690 while (ptr && ptr->type != XML_ELEMENT_NODE)
692 yaz_xml2query_rpnstructure(ptr, &zc->s2, odr, error_code, addinfo);
696 Z_Operand *s = (Z_Operand *) odr_malloc(odr, sizeof(Z_Operand));
697 (*zs)->which = Z_RPNStructure_simple;
699 if (!xmlStrcmp(ptr->name, BAD_CAST "apt"))
701 s->which = Z_Operand_APT;
702 yaz_xml2query_apt(ptr, &s->u.attributesPlusTerm,
703 odr, error_code, addinfo);
705 else if (!xmlStrcmp(ptr->name, BAD_CAST "rset"))
707 s->which = Z_Operand_resultSetId;
708 yaz_xml2query_rset(ptr, &s->u.resultSetId,
709 odr, error_code, addinfo);
714 *addinfo = "bad element: expected binary, apt or rset";
719 void yaz_xml2query_rpn(const xmlNode *ptr, Z_RPNQuery **query, ODR odr,
720 int *error_code, const char **addinfo)
722 const char *set = (const char *)
723 xmlGetProp((xmlNodePtr) ptr, BAD_CAST "set");
725 *query = (Z_RPNQuery*) odr_malloc(odr, sizeof(Z_RPNQuery));
727 (*query)->attributeSetId = yaz_str_to_z3950oid(odr, CLASS_ATTSET, set);
729 (*query)->attributeSetId = 0;
730 yaz_xml2query_rpnstructure(ptr->children, &(*query)->RPNStructure,
731 odr, error_code, addinfo);
734 static void yaz_xml2query_(const xmlNode *ptr, Z_Query **query, ODR odr,
735 int *error_code, const char **addinfo)
737 if (ptr && ptr->type == XML_ELEMENT_NODE &&
738 !xmlStrcmp(ptr->name, BAD_CAST "query"))
742 while (ptr && ptr->type != XML_ELEMENT_NODE)
744 if (!ptr || ptr->type != XML_ELEMENT_NODE)
747 *addinfo = "missing query content";
750 type = (const char *) ptr->name;
752 *query = (Z_Query*) odr_malloc(odr, sizeof(Z_Query));
753 if (!type || !strcmp(type, "rpn"))
755 (*query)->which = Z_Query_type_1;
756 yaz_xml2query_rpn(ptr, &(*query)->u.type_1, odr,
757 error_code, addinfo);
759 else if (!strcmp(type, "ccl"))
762 *addinfo = "ccl not supported yet";
764 else if (!strcmp(type, "z39.58"))
767 *addinfo = "z39.58 not supported yet";
769 else if (!strcmp(type, "cql"))
772 *addinfo = "cql not supported yet";
777 *addinfo = "unsupported query type";
783 *addinfo = "missing query element";
787 void yaz_xml2query(const void *xmlnodep, Z_Query **query, ODR odr,
788 int *error_code, const char **addinfo)
790 yaz_xml2query_(xmlnodep, query, odr, error_code, addinfo);
799 * indent-tabs-mode: nil
801 * vim: shiftwidth=4 tabstop=8 expandtab