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