More Doxygen stuff; for auto-generated code too
[yaz-moved-to-github.git] / src / xmlquery.c
1 /*
2  * Copyright (C) 1995-2006, Index Data ApS
3  * All rights reserved.
4  *
5  * $Id: xmlquery.c,v 1.8 2006-04-20 20:50:51 adam Exp $
6  */
7
8 /** \file xmlquery.c
9     \brief Query / XML conversions
10 */
11
12 #include <stdio.h>
13 #include <string.h>
14 #include <assert.h>
15
16 #if HAVE_XML2
17 #include <libxml/parser.h>
18 #include <libxml/tree.h>
19
20 #include <yaz/logrpn.h>
21 #include <yaz/xmlquery.h>
22
23 void yaz_query2xml_attribute_element(const Z_AttributeElement *element,
24                                      xmlNodePtr parent)
25 {
26     char formstr[30];
27     const char *setname = 0;
28     
29     if (element->attributeSet)
30     {
31         oident *attrset;
32         attrset = oid_getentbyoid (element->attributeSet);
33         setname = attrset->desc;
34     }
35
36     if (element->which == Z_AttributeValue_numeric)
37     {
38         xmlNodePtr node = xmlNewChild(parent, 0, BAD_CAST "attr", 0);
39
40         if (setname)
41             xmlNewProp(node, BAD_CAST "set", BAD_CAST setname);
42
43         sprintf(formstr, "%d", *element->attributeType);
44         xmlNewProp(node, BAD_CAST "type", BAD_CAST formstr);
45
46         sprintf(formstr, "%d", *element->value.numeric);
47         xmlNewProp(node, BAD_CAST "value", BAD_CAST formstr);
48     }
49     else if (element->which == Z_AttributeValue_complex)
50     {
51         int i;
52         for (i = 0; i<element->value.complex->num_list; i++)
53         {
54             xmlNodePtr node = xmlNewChild(parent, 0, BAD_CAST "attr", 0);
55             
56             if (setname)
57                 xmlNewProp(node, BAD_CAST "set", BAD_CAST setname);
58             
59             sprintf(formstr, "%d", *element->attributeType);
60             xmlNewProp(node, BAD_CAST "type", BAD_CAST formstr);
61             
62             if (element->value.complex->list[i]->which ==
63                 Z_StringOrNumeric_string)
64             {
65                 xmlNewProp(node, BAD_CAST "value", BAD_CAST 
66                            element->value.complex->list[i]->u.string);
67             }
68             else if (element->value.complex->list[i]->which ==
69                      Z_StringOrNumeric_numeric)
70             {
71                 sprintf(formstr, "%d",
72                         *element->value.complex->list[i]->u.numeric);
73                 xmlNewProp(node, BAD_CAST "value", BAD_CAST formstr);
74             }
75         }
76     }
77 }
78
79
80 xmlNodePtr yaz_query2xml_term(const Z_Term *term,
81                               xmlNodePtr parent)
82 {
83     xmlNodePtr t = 0;
84     xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "term", 0);
85     char formstr[20];
86     const char *type = 0;
87
88     switch (term->which)
89     {
90     case Z_Term_general:
91         type = "general";
92         t = xmlNewTextLen(BAD_CAST term->u.general->buf, term->u.general->len);
93         break;
94     case Z_Term_numeric:
95         type = "numeric";
96         sprintf(formstr, "%d", *term->u.numeric);
97         t = xmlNewText(BAD_CAST formstr);       
98         break;
99     case Z_Term_characterString:
100         type = "string";
101         t = xmlNewText(BAD_CAST term->u.characterString);
102         break;
103     case Z_Term_oid:
104         type = "oid";
105         break;
106     case Z_Term_dateTime:
107         type = "dateTime";
108         break;
109     case Z_Term_external:
110         type = "external";
111         break;
112     case Z_Term_integerAndUnit:
113         type ="integerAndUnit";
114         break;
115     case Z_Term_null:
116         type = "null";
117         break;
118     default:
119         break;
120     }
121     if (t) /* got a term node ? */
122         xmlAddChild(node, t);
123     if (type)
124         xmlNewProp(node, BAD_CAST "type", BAD_CAST type);
125     return node;
126 }
127
128 xmlNodePtr yaz_query2xml_apt(const Z_AttributesPlusTerm *zapt,
129                              xmlNodePtr parent)
130 {
131     xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "apt", 0);
132     int num_attributes = zapt->attributes->num_attributes;
133     int i;
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);
137
138     return node;
139 }
140
141
142 void yaz_query2xml_operator(Z_Operator *op, xmlNodePtr node)
143 {
144     const char *type = 0;
145     switch(op->which)
146     {
147     case Z_Operator_and:
148         type = "and";
149         break;
150     case Z_Operator_or:
151         type = "or";
152         break;
153     case Z_Operator_and_not:
154         type = "not";
155         break;
156     case Z_Operator_prox:
157         type = "prox";
158         break;
159     default:
160         return;
161     }
162     xmlNewProp(node, BAD_CAST "type", BAD_CAST type);
163     
164     if (op->which == Z_Operator_prox)
165     {
166         char formstr[30];
167         
168         if (op->u.prox->exclusion)
169         {
170             if (*op->u.prox->exclusion)
171                 xmlNewProp(node, BAD_CAST "exclusion", BAD_CAST "true");
172             else
173                 xmlNewProp(node, BAD_CAST "exclusion", BAD_CAST "false");
174         }
175         sprintf(formstr, "%d", *op->u.prox->distance);
176         xmlNewProp(node, BAD_CAST "distance", BAD_CAST formstr);
177
178         if (*op->u.prox->ordered)
179             xmlNewProp(node, BAD_CAST "ordered", BAD_CAST "true");
180         else 
181             xmlNewProp(node, BAD_CAST "ordered", BAD_CAST "false");
182        
183         sprintf(formstr, "%d", *op->u.prox->relationType);
184         xmlNewProp(node, BAD_CAST "relationType", BAD_CAST formstr);
185         
186         switch(op->u.prox->which)
187         {
188         case Z_ProximityOperator_known:
189             sprintf(formstr, "%d", *op->u.prox->u.known);
190             xmlNewProp(node, BAD_CAST "knownProximityUnit",
191                        BAD_CAST formstr);
192             break;
193         case Z_ProximityOperator_private:
194         default:
195             xmlNewProp(node, BAD_CAST "privateProximityUnit",
196                        BAD_CAST "private");
197             break;
198         }
199     }
200 }
201
202 xmlNodePtr yaz_query2xml_rpnstructure(const Z_RPNStructure *zs,
203                                       xmlNodePtr parent)
204 {
205     if (zs->which == Z_RPNStructure_complex)
206     {
207         Z_Complex *zc = zs->u.complex;
208
209         xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "operator", 0);
210         if (zc->roperator)
211             yaz_query2xml_operator(zc->roperator, node);
212         yaz_query2xml_rpnstructure(zc->s1, node);
213         yaz_query2xml_rpnstructure(zc->s2, node);
214         return node;
215     }
216     else if (zs->which == Z_RPNStructure_simple)
217     {
218         if (zs->u.simple->which == Z_Operand_APT)
219             return yaz_query2xml_apt(zs->u.simple->u.attributesPlusTerm,
220                                      parent);
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);
224     }
225     return 0;
226 }
227
228 xmlNodePtr yaz_query2xml_rpn(const Z_RPNQuery *rpn, xmlNodePtr parent)
229 {
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);
234 }
235
236 xmlNodePtr yaz_query2xml_ccl(const Odr_oct *ccl, xmlNodePtr node)
237 {
238     return 0;
239 }
240
241 xmlNodePtr yaz_query2xml_z3958(const Odr_oct *ccl, xmlNodePtr node)
242 {
243     return 0;
244 }
245
246 xmlNodePtr yaz_query2xml_cql(const char *cql, xmlNodePtr node)
247 {
248     return 0;
249 }
250
251 void yaz_rpnquery2xml(const Z_RPNQuery *rpn, void *docp_void)
252 {
253     Z_Query query;
254
255     query.which = Z_Query_type_1;
256     query.u.type_1 = (Z_RPNQuery *) rpn;
257     yaz_query2xml(&query, docp_void);
258 }
259
260 void yaz_query2xml(const Z_Query *q, void *docp_void)
261 {
262     xmlDocPtr *docp = (xmlDocPtr *) docp_void;
263     xmlNodePtr top_node, q_node = 0, child_node = 0;
264
265     assert(q);
266     assert(docp);
267
268     top_node = xmlNewNode(0, BAD_CAST "query");
269
270     switch (q->which)
271     {
272     case Z_Query_type_1: 
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);
276         break;
277     case Z_Query_type_2:
278         q_node = xmlNewChild(top_node, 0, BAD_CAST "ccl", 0);
279         child_node = yaz_query2xml_ccl(q->u.type_2, q_node);
280         break;
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);
284         break;
285     case Z_Query_type_104:
286         if (q->u.type_104->which == Z_External_CQL)
287         {
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);
290         }
291     }
292     if (child_node && q_node)
293     {
294         *docp = xmlNewDoc(BAD_CAST "1.0");
295         xmlDocSetRootElement(*docp, top_node); /* make it top node in doc */
296     }
297     else
298     {
299         *docp = 0;
300         xmlFreeNode(top_node);
301     }
302 }
303
304 bool_t *boolVal(ODR odr, const char *str)
305 {
306     if (*str == '\0' || strchr("0fF", *str))
307         return odr_intdup(odr, 0);
308     return odr_intdup(odr, 1);
309 }
310
311 int *intVal(ODR odr, const char *str)
312 {
313     return odr_intdup(odr, atoi(str));
314 }
315
316 void yaz_xml2query_operator(const xmlNode *ptr, Z_Operator **op,
317                             ODR odr, int *error_code, const char **addinfo)
318 {
319     const char *type = (const char *)
320         xmlGetProp((xmlNodePtr) ptr, BAD_CAST "type");
321     if (!type)
322     {
323         *error_code = 1;
324         *addinfo = "no operator type";
325         return;
326     }
327     *op = (Z_Operator*) odr_malloc(odr, sizeof(Z_Operator));
328     if (!strcmp(type, "and"))
329     {
330         (*op)->which = Z_Operator_and;
331         (*op)->u.op_and = odr_nullval();
332     }
333     else if (!strcmp(type, "or"))
334     {
335         (*op)->which = Z_Operator_or;
336         (*op)->u.op_or = odr_nullval();
337     }
338     else if (!strcmp(type, "not"))
339     {
340         (*op)->which = Z_Operator_and_not;
341         (*op)->u.and_not = odr_nullval();
342     }
343     else if (!strcmp(type, "prox"))
344     {
345         const char *atval;
346         Z_ProximityOperator *pop = (Z_ProximityOperator *) 
347             odr_malloc(odr, sizeof(Z_ProximityOperator));
348
349         (*op)->which = Z_Operator_prox;
350         (*op)->u.prox = pop;
351
352         atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
353                                           BAD_CAST "exclusion");
354         if (atval)
355             pop->exclusion = boolVal(odr, atval);
356         else
357             pop->exclusion = 0;
358
359         atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
360                                           BAD_CAST "distance");
361         if (atval)
362             pop->distance = intVal(odr, atval);
363         else
364             pop->distance = odr_intdup(odr, 1);
365
366         atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
367                                           BAD_CAST "ordered");
368         if (atval)
369             pop->ordered = boolVal(odr, atval);
370         else
371             pop->ordered = odr_intdup(odr, 1);
372
373         atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
374                                           BAD_CAST "relationType");
375         if (atval)
376             pop->relationType = intVal(odr, atval);
377         else
378             pop->relationType =
379                 odr_intdup(odr, Z_ProximityOperator_Prox_lessThanOrEqual);
380
381         atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
382                                           BAD_CAST "knownProximityUnit");
383         if (atval)
384         {
385             pop->which = Z_ProximityOperator_known;            
386             pop->u.known = intVal(odr, atval);
387         }
388         else
389         {
390             pop->which = Z_ProximityOperator_known;
391             pop->u.known = odr_intdup(odr, Z_ProxUnit_word);
392         }
393
394         atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
395                                           BAD_CAST "privateProximityUnit");
396         if (atval)
397         {
398             pop->which = Z_ProximityOperator_private;
399             pop->u.zprivate = intVal(odr, atval);
400         }
401     }
402     else
403     {
404         *error_code = 1;
405         *addinfo = "bad operator type";
406     }
407 }
408
409 void yaz_xml2query_attribute_element(const xmlNode *ptr, 
410                                      Z_AttributeElement **elem, ODR odr,
411                                      int *error_code, const char **addinfo)
412 {
413     int i;
414     xmlChar *set = 0;
415     xmlChar *type = 0;
416     xmlChar *value = 0;
417     int num_values = 0;
418     struct _xmlAttr *attr;
419     for (attr = ptr->properties; attr; attr = attr->next)
420     {
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)
429         {
430             value = attr->children->content;
431             num_values++;
432         }
433         else
434         {
435             *error_code = 1;
436             *addinfo = "bad attribute for attr content";
437             return;
438         }
439     }
440     if (!type)
441     {
442         *error_code = 1;
443         *addinfo = "missing type attribute for att content";
444         return;
445     }
446     if (!value)
447     {
448         *error_code = 1;
449         *addinfo = "missing value attribute for att content";
450         return;
451     }
452         
453     *elem = (Z_AttributeElement *) odr_malloc(odr, sizeof(**elem));
454     if (set)
455         (*elem)->attributeSet = yaz_str_to_z3950oid(odr, CLASS_ATTSET,
456                                                     (const char *)set);
457     else
458         (*elem)->attributeSet = 0;
459     (*elem)->attributeType = intVal(odr, (const char *) type);
460
461     /* looks like a number ? */
462     for (i = 0; value[i] && value[i] >= '0' && value[i] <= '9'; i++)
463         ;
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);
472
473         /* second pass over attr values */
474         i = 0;
475         for (attr = ptr->properties; attr; attr = attr->next)
476         {
477             if (!xmlStrcmp(attr->name, BAD_CAST "value") &&
478                 attr->children && attr->children->type == XML_TEXT_NODE)
479             {
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);
488                 i++;
489             }
490         }
491         (*elem)->value.complex->num_semanticAction = 0;
492         (*elem)->value.complex->semanticAction = 0;        
493     }
494     else
495     {   /* good'ld numeric value */
496         (*elem)->which = Z_AttributeValue_numeric;
497         (*elem)->value.numeric = intVal(odr, (const char *) value);
498     }
499 }
500
501 char *strVal(const xmlNode *ptr_cdata, ODR odr)
502 {
503     char *cdata;
504     int len = 0;
505     const xmlNode *ptr;
506
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);
511     *cdata = '\0';
512     for (ptr = ptr_cdata; ptr; ptr = ptr->next)
513         if (ptr->type == XML_TEXT_NODE)
514             strcat(cdata, (const char *) ptr->content);
515     return cdata;
516 }
517
518 void yaz_xml2query_term(const xmlNode *ptr,
519                        Z_Term **term, ODR odr,
520                        int *error_code, const char **addinfo)
521 {
522     xmlChar *type = 0;
523     struct _xmlAttr *attr;
524     char *cdata = strVal(ptr->children, odr);
525
526     for (attr = ptr->properties; attr; attr = attr->next)
527     {
528         if (!xmlStrcmp(attr->name, BAD_CAST "type") &&
529             attr->children && attr->children->type == XML_TEXT_NODE)
530             type = attr->children->content;
531         else
532         {
533             *error_code = 1;
534             *addinfo = "bad attribute for attr content";
535             return;
536         }
537     }
538     *term = (Z_Term *) odr_malloc(odr, sizeof(Z_Term));
539
540     if (!type || !xmlStrcmp(type, BAD_CAST "general"))
541     {
542         (*term)->which = Z_Term_general;
543         (*term)->u.general =
544             odr_create_Odr_oct(odr, (unsigned char *)cdata, strlen(cdata));
545     }
546     else if (!xmlStrcmp(type, BAD_CAST "numeric"))
547     {
548         (*term)->which = Z_Term_numeric;
549         (*term)->u.numeric = intVal(odr, cdata);
550     }
551     else if (!xmlStrcmp(type, BAD_CAST "string"))
552     {
553         (*term)->which = Z_Term_characterString;
554         (*term)->u.characterString = cdata;
555     }
556     else if (!xmlStrcmp(type, BAD_CAST "oid"))
557     {
558         *error_code = 1;
559         *addinfo = "unhandled term type: oid";
560     }
561     else if (!xmlStrcmp(type, BAD_CAST "dateTime"))
562     {
563         *error_code = 1;
564         *addinfo = "unhandled term type: dateTime";
565     }
566     else if (!xmlStrcmp(type, BAD_CAST "integerAndUnit"))
567     {
568         *error_code = 1;
569         *addinfo = "unhandled term type: integerAndUnit";
570     }
571     else if (!xmlStrcmp(type, BAD_CAST "null"))
572     {
573         (*term)->which = Z_Term_null;
574         (*term)->u.null = odr_nullval();
575     }
576     else
577     {
578         *error_code = 1;
579         *addinfo = "unhandled term type";
580     }
581 }
582
583 void yaz_xml2query_apt(const xmlNode *ptr_apt,
584                        Z_AttributesPlusTerm **zapt, ODR odr,
585                        int *error_code, const char **addinfo)
586 {
587     const xmlNode *ptr = ptr_apt->children;
588     int i, num_attr = 0;
589
590     *zapt = (Z_AttributesPlusTerm *)
591         odr_malloc(odr, sizeof(Z_AttributesPlusTerm));
592
593     /* deal with attributes */
594     (*zapt)->attributes = (Z_AttributeList*)
595         odr_malloc(odr, sizeof(Z_AttributeList));
596
597     /* how many attributes? */
598     for (; ptr; ptr = ptr->next)
599         if (ptr->type == XML_ELEMENT_NODE)
600         {
601             if (!xmlStrcmp(ptr->name, BAD_CAST "attr"))
602                 num_attr++;
603             else
604                 break;
605         }
606
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);
611
612     i = 0;    
613     ptr = ptr_apt->children;
614     for (; ptr; ptr = ptr->next)
615         if (ptr->type == XML_ELEMENT_NODE)
616         {
617             if (!xmlStrcmp(ptr->name, BAD_CAST "attr"))
618             {
619                 yaz_xml2query_attribute_element(
620                     ptr,  &(*zapt)->attributes->attributes[i], odr,
621                     error_code, addinfo);
622                 i++;
623             }
624             else
625                 break;
626         }
627     if (ptr && ptr->type == XML_ELEMENT_NODE)
628     {
629         if (!xmlStrcmp(ptr->name, BAD_CAST "term"))
630         {        
631             /* deal with term */
632             yaz_xml2query_term(ptr, &(*zapt)->term, odr, error_code, addinfo);
633         }
634         else
635         {
636             *error_code = 1;
637             *addinfo = "bad element in apt content";
638         }
639     }
640     else
641     {
642         *error_code = 1;
643         *addinfo = "missing term node in apt content";
644     }
645 }
646
647 void yaz_xml2query_rset(const xmlNode *ptr, Z_ResultSetId **rset,
648                         ODR odr, int *error_code, const char **addinfo)
649 {
650     if (ptr->children)
651     {
652         *rset = strVal(ptr->children, odr);
653     }
654     else
655     {
656         *error_code = 1;
657         *addinfo = "missing rset content";
658     }
659 }
660
661 void yaz_xml2query_rpnstructure(const xmlNode *ptr, Z_RPNStructure **zs,
662                                 ODR odr, int *error_code, const char **addinfo)
663 {
664     while (ptr && ptr->type != XML_ELEMENT_NODE)
665         ptr = ptr->next;
666     
667     if (!ptr || ptr->type != XML_ELEMENT_NODE)
668     {
669         *error_code = 1;
670         *addinfo = "missing rpn operator, rset, apt node";
671         return;
672     }
673     *zs = (Z_RPNStructure *) odr_malloc(odr, sizeof(Z_RPNStructure));
674     if (!xmlStrcmp(ptr->name, BAD_CAST "operator"))
675     {
676         Z_Complex *zc = odr_malloc(odr, sizeof(Z_Complex));
677         
678         (*zs)->which = Z_RPNStructure_complex;
679         (*zs)->u.complex = zc;
680         
681         yaz_xml2query_operator(ptr, &zc->roperator, odr, error_code, addinfo);
682
683         ptr = ptr->children;
684         while (ptr && ptr->type != XML_ELEMENT_NODE)
685             ptr = ptr->next;
686         yaz_xml2query_rpnstructure(ptr, &zc->s1, odr, error_code, addinfo);
687         if (ptr)
688             ptr = ptr->next;
689         while (ptr && ptr->type != XML_ELEMENT_NODE)
690             ptr = ptr->next;
691         yaz_xml2query_rpnstructure(ptr, &zc->s2, odr, error_code, addinfo);
692     }
693     else 
694     {
695         Z_Operand *s = (Z_Operand *) odr_malloc(odr, sizeof(Z_Operand));
696         (*zs)->which = Z_RPNStructure_simple;
697         (*zs)->u.simple = s;
698         if (!xmlStrcmp(ptr->name, BAD_CAST "apt"))
699         {
700             s->which = Z_Operand_APT;
701             yaz_xml2query_apt(ptr, &s->u.attributesPlusTerm,
702                               odr, error_code, addinfo);
703         }
704         else if (!xmlStrcmp(ptr->name, BAD_CAST "rset"))
705         {
706             s->which = Z_Operand_resultSetId; 
707             yaz_xml2query_rset(ptr, &s->u.resultSetId,
708                                odr, error_code, addinfo);
709         }
710         else
711         {
712             *error_code = 1;
713             *addinfo = "bad element: expected binary, apt or rset";
714         }        
715     }
716 }
717
718 void yaz_xml2query_rpn(const xmlNode *ptr, Z_RPNQuery **query, ODR odr,
719                    int *error_code, const char **addinfo)
720 {
721     const char *set = (const char *)
722         xmlGetProp((xmlNodePtr) ptr, BAD_CAST "set");
723
724     *query = (Z_RPNQuery*) odr_malloc(odr, sizeof(Z_RPNQuery));
725     if (set)
726         (*query)->attributeSetId = yaz_str_to_z3950oid(odr, CLASS_ATTSET, set);
727     else
728         (*query)->attributeSetId = 0;
729     yaz_xml2query_rpnstructure(ptr->children, &(*query)->RPNStructure,
730                                odr, error_code, addinfo);
731 }
732
733 static void yaz_xml2query_(const xmlNode *ptr, Z_Query **query, ODR odr,
734                            int *error_code, const char **addinfo)
735 {
736     if (ptr && ptr->type == XML_ELEMENT_NODE && 
737         !xmlStrcmp(ptr->name, BAD_CAST "query"))
738     {
739         const char *type;
740         ptr = ptr->children;
741         while (ptr && ptr->type != XML_ELEMENT_NODE)
742             ptr = ptr->next;
743         if (!ptr || ptr->type != XML_ELEMENT_NODE)
744         {
745             *error_code = 1;
746             *addinfo = "missing query content";
747             return;
748         }
749         type = (const char *) ptr->name;
750
751         *query = (Z_Query*) odr_malloc(odr, sizeof(Z_Query));
752         if (!type || !strcmp(type, "rpn"))
753         {
754             (*query)->which = Z_Query_type_1;
755             yaz_xml2query_rpn(ptr, &(*query)->u.type_1, odr,
756                               error_code, addinfo);
757         }
758         else if (!strcmp(type, "ccl"))
759         {
760             *error_code = 1;
761             *addinfo = "ccl not supported yet";
762         }
763         else if (!strcmp(type, "z39.58"))
764         {
765             *error_code = 1;
766             *addinfo = "z39.58 not supported yet";
767         }
768         else if (!strcmp(type, "cql"))
769         {
770             *error_code = 1;
771             *addinfo = "cql not supported yet";
772         }
773         else
774         {
775             *error_code = 1;
776             *addinfo = "unsupported query type";
777         }
778     }
779     else
780     {
781         *error_code = 1;
782         *addinfo = "missing query element";
783     }
784 }
785
786 void yaz_xml2query(const void *xmlnodep, Z_Query **query, ODR odr,
787                    int *error_code, const char **addinfo)
788 {
789     yaz_xml2query_(xmlnodep, query, odr, error_code, addinfo);
790 }
791
792 /* HAVE_XML2 */
793 #endif
794
795 /*
796  * Local variables:
797  * c-basic-offset: 4
798  * indent-tabs-mode: nil
799  * End:
800  * vim: shiftwidth=4 tabstop=8 expandtab
801  */