2 * Copyright (C) 1995-2006, Index Data ApS
5 * $Id: xmlquery.c,v 1.8 2006-04-20 20:50:51 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>
23 void yaz_query2xml_attribute_element(const Z_AttributeElement *element,
27 const char *setname = 0;
29 if (element->attributeSet)
32 attrset = oid_getentbyoid (element->attributeSet);
33 setname = attrset->desc;
36 if (element->which == Z_AttributeValue_numeric)
38 xmlNodePtr node = xmlNewChild(parent, 0, BAD_CAST "attr", 0);
41 xmlNewProp(node, BAD_CAST "set", BAD_CAST setname);
43 sprintf(formstr, "%d", *element->attributeType);
44 xmlNewProp(node, BAD_CAST "type", BAD_CAST formstr);
46 sprintf(formstr, "%d", *element->value.numeric);
47 xmlNewProp(node, BAD_CAST "value", BAD_CAST formstr);
49 else if (element->which == Z_AttributeValue_complex)
52 for (i = 0; i<element->value.complex->num_list; i++)
54 xmlNodePtr node = xmlNewChild(parent, 0, BAD_CAST "attr", 0);
57 xmlNewProp(node, BAD_CAST "set", BAD_CAST setname);
59 sprintf(formstr, "%d", *element->attributeType);
60 xmlNewProp(node, BAD_CAST "type", BAD_CAST formstr);
62 if (element->value.complex->list[i]->which ==
63 Z_StringOrNumeric_string)
65 xmlNewProp(node, BAD_CAST "value", BAD_CAST
66 element->value.complex->list[i]->u.string);
68 else if (element->value.complex->list[i]->which ==
69 Z_StringOrNumeric_numeric)
71 sprintf(formstr, "%d",
72 *element->value.complex->list[i]->u.numeric);
73 xmlNewProp(node, BAD_CAST "value", BAD_CAST formstr);
80 xmlNodePtr yaz_query2xml_term(const Z_Term *term,
84 xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "term", 0);
92 t = xmlNewTextLen(BAD_CAST term->u.general->buf, term->u.general->len);
96 sprintf(formstr, "%d", *term->u.numeric);
97 t = xmlNewText(BAD_CAST formstr);
99 case Z_Term_characterString:
101 t = xmlNewText(BAD_CAST term->u.characterString);
106 case Z_Term_dateTime:
109 case Z_Term_external:
112 case Z_Term_integerAndUnit:
113 type ="integerAndUnit";
121 if (t) /* got a term node ? */
122 xmlAddChild(node, t);
124 xmlNewProp(node, BAD_CAST "type", BAD_CAST type);
128 xmlNodePtr yaz_query2xml_apt(const Z_AttributesPlusTerm *zapt,
131 xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "apt", 0);
132 int num_attributes = zapt->attributes->num_attributes;
134 for (i = 0; i<num_attributes; i++)
135 yaz_query2xml_attribute_element(zapt->attributes->attributes[i], node);
136 yaz_query2xml_term(zapt->term, node);
142 void yaz_query2xml_operator(Z_Operator *op, xmlNodePtr node)
144 const char *type = 0;
153 case Z_Operator_and_not:
156 case Z_Operator_prox:
162 xmlNewProp(node, BAD_CAST "type", BAD_CAST type);
164 if (op->which == Z_Operator_prox)
168 if (op->u.prox->exclusion)
170 if (*op->u.prox->exclusion)
171 xmlNewProp(node, BAD_CAST "exclusion", BAD_CAST "true");
173 xmlNewProp(node, BAD_CAST "exclusion", BAD_CAST "false");
175 sprintf(formstr, "%d", *op->u.prox->distance);
176 xmlNewProp(node, BAD_CAST "distance", BAD_CAST formstr);
178 if (*op->u.prox->ordered)
179 xmlNewProp(node, BAD_CAST "ordered", BAD_CAST "true");
181 xmlNewProp(node, BAD_CAST "ordered", BAD_CAST "false");
183 sprintf(formstr, "%d", *op->u.prox->relationType);
184 xmlNewProp(node, BAD_CAST "relationType", BAD_CAST formstr);
186 switch(op->u.prox->which)
188 case Z_ProximityOperator_known:
189 sprintf(formstr, "%d", *op->u.prox->u.known);
190 xmlNewProp(node, BAD_CAST "knownProximityUnit",
193 case Z_ProximityOperator_private:
195 xmlNewProp(node, BAD_CAST "privateProximityUnit",
202 xmlNodePtr yaz_query2xml_rpnstructure(const Z_RPNStructure *zs,
205 if (zs->which == Z_RPNStructure_complex)
207 Z_Complex *zc = zs->u.complex;
209 xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "operator", 0);
211 yaz_query2xml_operator(zc->roperator, node);
212 yaz_query2xml_rpnstructure(zc->s1, node);
213 yaz_query2xml_rpnstructure(zc->s2, node);
216 else if (zs->which == Z_RPNStructure_simple)
218 if (zs->u.simple->which == Z_Operand_APT)
219 return yaz_query2xml_apt(zs->u.simple->u.attributesPlusTerm,
221 else if (zs->u.simple->which == Z_Operand_resultSetId)
222 return xmlNewChild(parent, /* NS */ 0, BAD_CAST "rset",
223 BAD_CAST zs->u.simple->u.resultSetId);
228 xmlNodePtr yaz_query2xml_rpn(const Z_RPNQuery *rpn, xmlNodePtr parent)
230 oident *attrset = oid_getentbyoid (rpn->attributeSetId);
231 if (attrset && attrset->value)
232 xmlNewProp(parent, BAD_CAST "set", BAD_CAST attrset->desc);
233 return yaz_query2xml_rpnstructure(rpn->RPNStructure, parent);
236 xmlNodePtr yaz_query2xml_ccl(const Odr_oct *ccl, xmlNodePtr node)
241 xmlNodePtr yaz_query2xml_z3958(const Odr_oct *ccl, xmlNodePtr node)
246 xmlNodePtr yaz_query2xml_cql(const char *cql, xmlNodePtr node)
251 void yaz_rpnquery2xml(const Z_RPNQuery *rpn, void *docp_void)
255 query.which = Z_Query_type_1;
256 query.u.type_1 = (Z_RPNQuery *) rpn;
257 yaz_query2xml(&query, docp_void);
260 void yaz_query2xml(const Z_Query *q, void *docp_void)
262 xmlDocPtr *docp = (xmlDocPtr *) docp_void;
263 xmlNodePtr top_node, q_node = 0, child_node = 0;
268 top_node = xmlNewNode(0, BAD_CAST "query");
273 case Z_Query_type_101:
274 q_node = xmlNewChild(top_node, 0, BAD_CAST "rpn", 0);
275 child_node = yaz_query2xml_rpn(q->u.type_1, q_node);
278 q_node = xmlNewChild(top_node, 0, BAD_CAST "ccl", 0);
279 child_node = yaz_query2xml_ccl(q->u.type_2, q_node);
281 case Z_Query_type_100:
282 q_node = xmlNewChild(top_node, 0, BAD_CAST "z39.58", 0);
283 child_node = yaz_query2xml_z3958(q->u.type_100, q_node);
285 case Z_Query_type_104:
286 if (q->u.type_104->which == Z_External_CQL)
288 q_node = xmlNewChild(top_node, 0, BAD_CAST "cql", 0);
289 child_node = yaz_query2xml_cql(q->u.type_104->u.cql, q_node);
292 if (child_node && q_node)
294 *docp = xmlNewDoc(BAD_CAST "1.0");
295 xmlDocSetRootElement(*docp, top_node); /* make it top node in doc */
300 xmlFreeNode(top_node);
304 bool_t *boolVal(ODR odr, const char *str)
306 if (*str == '\0' || strchr("0fF", *str))
307 return odr_intdup(odr, 0);
308 return odr_intdup(odr, 1);
311 int *intVal(ODR odr, const char *str)
313 return odr_intdup(odr, atoi(str));
316 void yaz_xml2query_operator(const xmlNode *ptr, Z_Operator **op,
317 ODR odr, int *error_code, const char **addinfo)
319 const char *type = (const char *)
320 xmlGetProp((xmlNodePtr) ptr, BAD_CAST "type");
324 *addinfo = "no operator type";
327 *op = (Z_Operator*) odr_malloc(odr, sizeof(Z_Operator));
328 if (!strcmp(type, "and"))
330 (*op)->which = Z_Operator_and;
331 (*op)->u.op_and = odr_nullval();
333 else if (!strcmp(type, "or"))
335 (*op)->which = Z_Operator_or;
336 (*op)->u.op_or = odr_nullval();
338 else if (!strcmp(type, "not"))
340 (*op)->which = Z_Operator_and_not;
341 (*op)->u.and_not = odr_nullval();
343 else if (!strcmp(type, "prox"))
346 Z_ProximityOperator *pop = (Z_ProximityOperator *)
347 odr_malloc(odr, sizeof(Z_ProximityOperator));
349 (*op)->which = Z_Operator_prox;
352 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
353 BAD_CAST "exclusion");
355 pop->exclusion = boolVal(odr, atval);
359 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
360 BAD_CAST "distance");
362 pop->distance = intVal(odr, atval);
364 pop->distance = odr_intdup(odr, 1);
366 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
369 pop->ordered = boolVal(odr, atval);
371 pop->ordered = odr_intdup(odr, 1);
373 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
374 BAD_CAST "relationType");
376 pop->relationType = intVal(odr, atval);
379 odr_intdup(odr, Z_ProximityOperator_Prox_lessThanOrEqual);
381 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
382 BAD_CAST "knownProximityUnit");
385 pop->which = Z_ProximityOperator_known;
386 pop->u.known = intVal(odr, atval);
390 pop->which = Z_ProximityOperator_known;
391 pop->u.known = odr_intdup(odr, Z_ProxUnit_word);
394 atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
395 BAD_CAST "privateProximityUnit");
398 pop->which = Z_ProximityOperator_private;
399 pop->u.zprivate = intVal(odr, atval);
405 *addinfo = "bad operator type";
409 void yaz_xml2query_attribute_element(const xmlNode *ptr,
410 Z_AttributeElement **elem, ODR odr,
411 int *error_code, const char **addinfo)
418 struct _xmlAttr *attr;
419 for (attr = ptr->properties; attr; attr = attr->next)
421 if (!xmlStrcmp(attr->name, BAD_CAST "set") &&
422 attr->children && attr->children->type == XML_TEXT_NODE)
423 set = attr->children->content;
424 else if (!xmlStrcmp(attr->name, BAD_CAST "type") &&
425 attr->children && attr->children->type == XML_TEXT_NODE)
426 type = attr->children->content;
427 else if (!xmlStrcmp(attr->name, BAD_CAST "value") &&
428 attr->children && attr->children->type == XML_TEXT_NODE)
430 value = attr->children->content;
436 *addinfo = "bad attribute for attr content";
443 *addinfo = "missing type attribute for att content";
449 *addinfo = "missing value attribute for att content";
453 *elem = (Z_AttributeElement *) odr_malloc(odr, sizeof(**elem));
455 (*elem)->attributeSet = yaz_str_to_z3950oid(odr, CLASS_ATTSET,
458 (*elem)->attributeSet = 0;
459 (*elem)->attributeType = intVal(odr, (const char *) type);
461 /* looks like a number ? */
462 for (i = 0; value[i] && value[i] >= '0' && value[i] <= '9'; i++)
464 if (num_values > 1 || value[i])
465 { /* multiple values or string, so turn to complex attribute */
466 (*elem)->which = Z_AttributeValue_complex;
467 (*elem)->value.complex =
468 (Z_ComplexAttribute*) odr_malloc(odr, sizeof(Z_ComplexAttribute));
469 (*elem)->value.complex->num_list = num_values;
470 (*elem)->value.complex->list = (Z_StringOrNumeric **)
471 odr_malloc(odr, sizeof(Z_StringOrNumeric*) * num_values);
473 /* second pass over attr values */
475 for (attr = ptr->properties; attr; attr = attr->next)
477 if (!xmlStrcmp(attr->name, BAD_CAST "value") &&
478 attr->children && attr->children->type == XML_TEXT_NODE)
480 const char *val = (const char *) attr->children->content;
481 assert (i < num_values);
482 (*elem)->value.complex->list[i] = (Z_StringOrNumeric *)
483 odr_malloc(odr, sizeof(Z_StringOrNumeric));
484 (*elem)->value.complex->list[i]->which =
485 Z_StringOrNumeric_string;
486 (*elem)->value.complex->list[i]->u.string =
487 odr_strdup(odr, val);
491 (*elem)->value.complex->num_semanticAction = 0;
492 (*elem)->value.complex->semanticAction = 0;
495 { /* good'ld numeric value */
496 (*elem)->which = Z_AttributeValue_numeric;
497 (*elem)->value.numeric = intVal(odr, (const char *) value);
501 char *strVal(const xmlNode *ptr_cdata, ODR odr)
507 for (ptr = ptr_cdata; ptr; ptr = ptr->next)
508 if (ptr->type == XML_TEXT_NODE)
509 len += xmlStrlen(ptr->content);
510 cdata = (char *) odr_malloc(odr, len+1);
512 for (ptr = ptr_cdata; ptr; ptr = ptr->next)
513 if (ptr->type == XML_TEXT_NODE)
514 strcat(cdata, (const char *) ptr->content);
518 void yaz_xml2query_term(const xmlNode *ptr,
519 Z_Term **term, ODR odr,
520 int *error_code, const char **addinfo)
523 struct _xmlAttr *attr;
524 char *cdata = strVal(ptr->children, odr);
526 for (attr = ptr->properties; attr; attr = attr->next)
528 if (!xmlStrcmp(attr->name, BAD_CAST "type") &&
529 attr->children && attr->children->type == XML_TEXT_NODE)
530 type = attr->children->content;
534 *addinfo = "bad attribute for attr content";
538 *term = (Z_Term *) odr_malloc(odr, sizeof(Z_Term));
540 if (!type || !xmlStrcmp(type, BAD_CAST "general"))
542 (*term)->which = Z_Term_general;
544 odr_create_Odr_oct(odr, (unsigned char *)cdata, strlen(cdata));
546 else if (!xmlStrcmp(type, BAD_CAST "numeric"))
548 (*term)->which = Z_Term_numeric;
549 (*term)->u.numeric = intVal(odr, cdata);
551 else if (!xmlStrcmp(type, BAD_CAST "string"))
553 (*term)->which = Z_Term_characterString;
554 (*term)->u.characterString = cdata;
556 else if (!xmlStrcmp(type, BAD_CAST "oid"))
559 *addinfo = "unhandled term type: oid";
561 else if (!xmlStrcmp(type, BAD_CAST "dateTime"))
564 *addinfo = "unhandled term type: dateTime";
566 else if (!xmlStrcmp(type, BAD_CAST "integerAndUnit"))
569 *addinfo = "unhandled term type: integerAndUnit";
571 else if (!xmlStrcmp(type, BAD_CAST "null"))
573 (*term)->which = Z_Term_null;
574 (*term)->u.null = odr_nullval();
579 *addinfo = "unhandled term type";
583 void yaz_xml2query_apt(const xmlNode *ptr_apt,
584 Z_AttributesPlusTerm **zapt, ODR odr,
585 int *error_code, const char **addinfo)
587 const xmlNode *ptr = ptr_apt->children;
590 *zapt = (Z_AttributesPlusTerm *)
591 odr_malloc(odr, sizeof(Z_AttributesPlusTerm));
593 /* deal with attributes */
594 (*zapt)->attributes = (Z_AttributeList*)
595 odr_malloc(odr, sizeof(Z_AttributeList));
597 /* how many attributes? */
598 for (; ptr; ptr = ptr->next)
599 if (ptr->type == XML_ELEMENT_NODE)
601 if (!xmlStrcmp(ptr->name, BAD_CAST "attr"))
607 /* allocate and parse for real */
608 (*zapt)->attributes->num_attributes = num_attr;
609 (*zapt)->attributes->attributes = (Z_AttributeElement **)
610 odr_malloc(odr, sizeof(Z_AttributeElement*) * num_attr);
613 ptr = ptr_apt->children;
614 for (; ptr; ptr = ptr->next)
615 if (ptr->type == XML_ELEMENT_NODE)
617 if (!xmlStrcmp(ptr->name, BAD_CAST "attr"))
619 yaz_xml2query_attribute_element(
620 ptr, &(*zapt)->attributes->attributes[i], odr,
621 error_code, addinfo);
627 if (ptr && ptr->type == XML_ELEMENT_NODE)
629 if (!xmlStrcmp(ptr->name, BAD_CAST "term"))
632 yaz_xml2query_term(ptr, &(*zapt)->term, odr, error_code, addinfo);
637 *addinfo = "bad element in apt content";
643 *addinfo = "missing term node in apt content";
647 void yaz_xml2query_rset(const xmlNode *ptr, Z_ResultSetId **rset,
648 ODR odr, int *error_code, const char **addinfo)
652 *rset = strVal(ptr->children, odr);
657 *addinfo = "missing rset content";
661 void yaz_xml2query_rpnstructure(const xmlNode *ptr, Z_RPNStructure **zs,
662 ODR odr, int *error_code, const char **addinfo)
664 while (ptr && ptr->type != XML_ELEMENT_NODE)
667 if (!ptr || ptr->type != XML_ELEMENT_NODE)
670 *addinfo = "missing rpn operator, rset, apt node";
673 *zs = (Z_RPNStructure *) odr_malloc(odr, sizeof(Z_RPNStructure));
674 if (!xmlStrcmp(ptr->name, BAD_CAST "operator"))
676 Z_Complex *zc = odr_malloc(odr, sizeof(Z_Complex));
678 (*zs)->which = Z_RPNStructure_complex;
679 (*zs)->u.complex = zc;
681 yaz_xml2query_operator(ptr, &zc->roperator, odr, error_code, addinfo);
684 while (ptr && ptr->type != XML_ELEMENT_NODE)
686 yaz_xml2query_rpnstructure(ptr, &zc->s1, odr, error_code, addinfo);
689 while (ptr && ptr->type != XML_ELEMENT_NODE)
691 yaz_xml2query_rpnstructure(ptr, &zc->s2, odr, error_code, addinfo);
695 Z_Operand *s = (Z_Operand *) odr_malloc(odr, sizeof(Z_Operand));
696 (*zs)->which = Z_RPNStructure_simple;
698 if (!xmlStrcmp(ptr->name, BAD_CAST "apt"))
700 s->which = Z_Operand_APT;
701 yaz_xml2query_apt(ptr, &s->u.attributesPlusTerm,
702 odr, error_code, addinfo);
704 else if (!xmlStrcmp(ptr->name, BAD_CAST "rset"))
706 s->which = Z_Operand_resultSetId;
707 yaz_xml2query_rset(ptr, &s->u.resultSetId,
708 odr, error_code, addinfo);
713 *addinfo = "bad element: expected binary, apt or rset";
718 void yaz_xml2query_rpn(const xmlNode *ptr, Z_RPNQuery **query, ODR odr,
719 int *error_code, const char **addinfo)
721 const char *set = (const char *)
722 xmlGetProp((xmlNodePtr) ptr, BAD_CAST "set");
724 *query = (Z_RPNQuery*) odr_malloc(odr, sizeof(Z_RPNQuery));
726 (*query)->attributeSetId = yaz_str_to_z3950oid(odr, CLASS_ATTSET, set);
728 (*query)->attributeSetId = 0;
729 yaz_xml2query_rpnstructure(ptr->children, &(*query)->RPNStructure,
730 odr, error_code, addinfo);
733 static void yaz_xml2query_(const xmlNode *ptr, Z_Query **query, ODR odr,
734 int *error_code, const char **addinfo)
736 if (ptr && ptr->type == XML_ELEMENT_NODE &&
737 !xmlStrcmp(ptr->name, BAD_CAST "query"))
741 while (ptr && ptr->type != XML_ELEMENT_NODE)
743 if (!ptr || ptr->type != XML_ELEMENT_NODE)
746 *addinfo = "missing query content";
749 type = (const char *) ptr->name;
751 *query = (Z_Query*) odr_malloc(odr, sizeof(Z_Query));
752 if (!type || !strcmp(type, "rpn"))
754 (*query)->which = Z_Query_type_1;
755 yaz_xml2query_rpn(ptr, &(*query)->u.type_1, odr,
756 error_code, addinfo);
758 else if (!strcmp(type, "ccl"))
761 *addinfo = "ccl not supported yet";
763 else if (!strcmp(type, "z39.58"))
766 *addinfo = "z39.58 not supported yet";
768 else if (!strcmp(type, "cql"))
771 *addinfo = "cql not supported yet";
776 *addinfo = "unsupported query type";
782 *addinfo = "missing query element";
786 void yaz_xml2query(const void *xmlnodep, Z_Query **query, ODR odr,
787 int *error_code, const char **addinfo)
789 yaz_xml2query_(xmlnodep, query, odr, error_code, addinfo);
798 * indent-tabs-mode: nil
800 * vim: shiftwidth=4 tabstop=8 expandtab