For Libxml2 and friends, YAZ defines YAZ_HAVE_{XML2,XSLT,EXSLT) in
[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.10 2006-07-06 10:17:54 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 YAZ_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, xmlDocPtr *docp)
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);
258 }
259
260 void yaz_query2xml(const Z_Query *q, xmlDocPtr *docp)
261 {
262     xmlNodePtr top_node, q_node = 0, child_node = 0;
263
264     assert(q);
265     assert(docp);
266
267     top_node = xmlNewNode(0, BAD_CAST "query");
268
269     switch (q->which)
270     {
271     case Z_Query_type_1: 
272     case Z_Query_type_101:
273         q_node = xmlNewChild(top_node, 0, BAD_CAST "rpn", 0);
274         child_node = yaz_query2xml_rpn(q->u.type_1, q_node);
275         break;
276     case Z_Query_type_2:
277         q_node = xmlNewChild(top_node, 0, BAD_CAST "ccl", 0);
278         child_node = yaz_query2xml_ccl(q->u.type_2, q_node);
279         break;
280     case Z_Query_type_100:
281         q_node = xmlNewChild(top_node, 0, BAD_CAST "z39.58", 0);
282         child_node = yaz_query2xml_z3958(q->u.type_100, q_node);
283         break;
284     case Z_Query_type_104:
285         if (q->u.type_104->which == Z_External_CQL)
286         {
287             q_node = xmlNewChild(top_node, 0, BAD_CAST "cql", 0);
288             child_node = yaz_query2xml_cql(q->u.type_104->u.cql, q_node);
289         }
290     }
291     if (child_node && q_node)
292     {
293         *docp = xmlNewDoc(BAD_CAST "1.0");
294         xmlDocSetRootElement(*docp, top_node); /* make it top node in doc */
295     }
296     else
297     {
298         *docp = 0;
299         xmlFreeNode(top_node);
300     }
301 }
302
303 bool_t *boolVal(ODR odr, const char *str)
304 {
305     if (*str == '\0' || strchr("0fF", *str))
306         return odr_intdup(odr, 0);
307     return odr_intdup(odr, 1);
308 }
309
310 int *intVal(ODR odr, const char *str)
311 {
312     return odr_intdup(odr, atoi(str));
313 }
314
315 void yaz_xml2query_operator(const xmlNode *ptr, Z_Operator **op,
316                             ODR odr, int *error_code, const char **addinfo)
317 {
318     const char *type = (const char *)
319         xmlGetProp((xmlNodePtr) ptr, BAD_CAST "type");
320     if (!type)
321     {
322         *error_code = 1;
323         *addinfo = "no operator type";
324         return;
325     }
326     *op = (Z_Operator*) odr_malloc(odr, sizeof(Z_Operator));
327     if (!strcmp(type, "and"))
328     {
329         (*op)->which = Z_Operator_and;
330         (*op)->u.op_and = odr_nullval();
331     }
332     else if (!strcmp(type, "or"))
333     {
334         (*op)->which = Z_Operator_or;
335         (*op)->u.op_or = odr_nullval();
336     }
337     else if (!strcmp(type, "not"))
338     {
339         (*op)->which = Z_Operator_and_not;
340         (*op)->u.and_not = odr_nullval();
341     }
342     else if (!strcmp(type, "prox"))
343     {
344         const char *atval;
345         Z_ProximityOperator *pop = (Z_ProximityOperator *) 
346             odr_malloc(odr, sizeof(Z_ProximityOperator));
347
348         (*op)->which = Z_Operator_prox;
349         (*op)->u.prox = pop;
350
351         atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
352                                           BAD_CAST "exclusion");
353         if (atval)
354             pop->exclusion = boolVal(odr, atval);
355         else
356             pop->exclusion = 0;
357
358         atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
359                                           BAD_CAST "distance");
360         if (atval)
361             pop->distance = intVal(odr, atval);
362         else
363             pop->distance = odr_intdup(odr, 1);
364
365         atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
366                                           BAD_CAST "ordered");
367         if (atval)
368             pop->ordered = boolVal(odr, atval);
369         else
370             pop->ordered = odr_intdup(odr, 1);
371
372         atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
373                                           BAD_CAST "relationType");
374         if (atval)
375             pop->relationType = intVal(odr, atval);
376         else
377             pop->relationType =
378                 odr_intdup(odr, Z_ProximityOperator_Prox_lessThanOrEqual);
379
380         atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
381                                           BAD_CAST "knownProximityUnit");
382         if (atval)
383         {
384             pop->which = Z_ProximityOperator_known;            
385             pop->u.known = intVal(odr, atval);
386         }
387         else
388         {
389             pop->which = Z_ProximityOperator_known;
390             pop->u.known = odr_intdup(odr, Z_ProxUnit_word);
391         }
392
393         atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
394                                           BAD_CAST "privateProximityUnit");
395         if (atval)
396         {
397             pop->which = Z_ProximityOperator_private;
398             pop->u.zprivate = intVal(odr, atval);
399         }
400     }
401     else
402     {
403         *error_code = 1;
404         *addinfo = "bad operator type";
405     }
406 }
407
408 void yaz_xml2query_attribute_element(const xmlNode *ptr, 
409                                      Z_AttributeElement **elem, ODR odr,
410                                      int *error_code, const char **addinfo)
411 {
412     int i;
413     xmlChar *set = 0;
414     xmlChar *type = 0;
415     xmlChar *value = 0;
416     int num_values = 0;
417     struct _xmlAttr *attr;
418     for (attr = ptr->properties; attr; attr = attr->next)
419     {
420         if (!xmlStrcmp(attr->name, BAD_CAST "set") &&
421             attr->children && attr->children->type == XML_TEXT_NODE)
422             set = attr->children->content;
423         else if (!xmlStrcmp(attr->name, BAD_CAST "type") &&
424             attr->children && attr->children->type == XML_TEXT_NODE)
425             type = attr->children->content;
426         else if (!xmlStrcmp(attr->name, BAD_CAST "value") &&
427             attr->children && attr->children->type == XML_TEXT_NODE)
428         {
429             value = attr->children->content;
430             num_values++;
431         }
432         else
433         {
434             *error_code = 1;
435             *addinfo = "bad attribute for attr content";
436             return;
437         }
438     }
439     if (!type)
440     {
441         *error_code = 1;
442         *addinfo = "missing type attribute for att content";
443         return;
444     }
445     if (!value)
446     {
447         *error_code = 1;
448         *addinfo = "missing value attribute for att content";
449         return;
450     }
451         
452     *elem = (Z_AttributeElement *) odr_malloc(odr, sizeof(**elem));
453     if (set)
454         (*elem)->attributeSet = yaz_str_to_z3950oid(odr, CLASS_ATTSET,
455                                                     (const char *)set);
456     else
457         (*elem)->attributeSet = 0;
458     (*elem)->attributeType = intVal(odr, (const char *) type);
459
460     /* looks like a number ? */
461     for (i = 0; value[i] && value[i] >= '0' && value[i] <= '9'; i++)
462         ;
463     if (num_values > 1 || value[i])
464     {   /* multiple values or string, so turn to complex attribute */
465         (*elem)->which = Z_AttributeValue_complex;
466         (*elem)->value.complex =
467             (Z_ComplexAttribute*) odr_malloc(odr, sizeof(Z_ComplexAttribute));
468         (*elem)->value.complex->num_list = num_values;
469         (*elem)->value.complex->list = (Z_StringOrNumeric **)
470             odr_malloc(odr, sizeof(Z_StringOrNumeric*) * num_values);
471
472         /* second pass over attr values */
473         i = 0;
474         for (attr = ptr->properties; attr; attr = attr->next)
475         {
476             if (!xmlStrcmp(attr->name, BAD_CAST "value") &&
477                 attr->children && attr->children->type == XML_TEXT_NODE)
478             {
479                 const char *val = (const char *) attr->children->content;
480                 assert (i < num_values);
481                 (*elem)->value.complex->list[i] = (Z_StringOrNumeric *)
482                     odr_malloc(odr, sizeof(Z_StringOrNumeric));
483                 (*elem)->value.complex->list[i]->which =
484                     Z_StringOrNumeric_string;
485                 (*elem)->value.complex->list[i]->u.string =
486                     odr_strdup(odr, val);
487                 i++;
488             }
489         }
490         (*elem)->value.complex->num_semanticAction = 0;
491         (*elem)->value.complex->semanticAction = 0;        
492     }
493     else
494     {   /* good'ld numeric value */
495         (*elem)->which = Z_AttributeValue_numeric;
496         (*elem)->value.numeric = intVal(odr, (const char *) value);
497     }
498 }
499
500 char *strVal(const xmlNode *ptr_cdata, ODR odr)
501 {
502     return nmem_text_node_cdata(ptr_cdata, odr->mem);
503 }
504
505 void yaz_xml2query_term(const xmlNode *ptr,
506                        Z_Term **term, ODR odr,
507                        int *error_code, const char **addinfo)
508 {
509     xmlChar *type = 0;
510     struct _xmlAttr *attr;
511     char *cdata = strVal(ptr->children, odr);
512
513     for (attr = ptr->properties; attr; attr = attr->next)
514     {
515         if (!xmlStrcmp(attr->name, BAD_CAST "type") &&
516             attr->children && attr->children->type == XML_TEXT_NODE)
517             type = attr->children->content;
518         else
519         {
520             *error_code = 1;
521             *addinfo = "bad attribute for attr content";
522             return;
523         }
524     }
525     *term = (Z_Term *) odr_malloc(odr, sizeof(Z_Term));
526
527     if (!type || !xmlStrcmp(type, BAD_CAST "general"))
528     {
529         (*term)->which = Z_Term_general;
530         (*term)->u.general =
531             odr_create_Odr_oct(odr, (unsigned char *)cdata, strlen(cdata));
532     }
533     else if (!xmlStrcmp(type, BAD_CAST "numeric"))
534     {
535         (*term)->which = Z_Term_numeric;
536         (*term)->u.numeric = intVal(odr, cdata);
537     }
538     else if (!xmlStrcmp(type, BAD_CAST "string"))
539     {
540         (*term)->which = Z_Term_characterString;
541         (*term)->u.characterString = cdata;
542     }
543     else if (!xmlStrcmp(type, BAD_CAST "oid"))
544     {
545         *error_code = 1;
546         *addinfo = "unhandled term type: oid";
547     }
548     else if (!xmlStrcmp(type, BAD_CAST "dateTime"))
549     {
550         *error_code = 1;
551         *addinfo = "unhandled term type: dateTime";
552     }
553     else if (!xmlStrcmp(type, BAD_CAST "integerAndUnit"))
554     {
555         *error_code = 1;
556         *addinfo = "unhandled term type: integerAndUnit";
557     }
558     else if (!xmlStrcmp(type, BAD_CAST "null"))
559     {
560         (*term)->which = Z_Term_null;
561         (*term)->u.null = odr_nullval();
562     }
563     else
564     {
565         *error_code = 1;
566         *addinfo = "unhandled term type";
567     }
568 }
569
570 void yaz_xml2query_apt(const xmlNode *ptr_apt,
571                        Z_AttributesPlusTerm **zapt, ODR odr,
572                        int *error_code, const char **addinfo)
573 {
574     const xmlNode *ptr = ptr_apt->children;
575     int i, num_attr = 0;
576
577     *zapt = (Z_AttributesPlusTerm *)
578         odr_malloc(odr, sizeof(Z_AttributesPlusTerm));
579
580     /* deal with attributes */
581     (*zapt)->attributes = (Z_AttributeList*)
582         odr_malloc(odr, sizeof(Z_AttributeList));
583
584     /* how many attributes? */
585     for (; ptr; ptr = ptr->next)
586         if (ptr->type == XML_ELEMENT_NODE)
587         {
588             if (!xmlStrcmp(ptr->name, BAD_CAST "attr"))
589                 num_attr++;
590             else
591                 break;
592         }
593
594     /* allocate and parse for real */
595     (*zapt)->attributes->num_attributes = num_attr;
596     (*zapt)->attributes->attributes = (Z_AttributeElement **)
597         odr_malloc(odr, sizeof(Z_AttributeElement*) * num_attr);
598
599     i = 0;    
600     ptr = ptr_apt->children;
601     for (; ptr; ptr = ptr->next)
602         if (ptr->type == XML_ELEMENT_NODE)
603         {
604             if (!xmlStrcmp(ptr->name, BAD_CAST "attr"))
605             {
606                 yaz_xml2query_attribute_element(
607                     ptr,  &(*zapt)->attributes->attributes[i], odr,
608                     error_code, addinfo);
609                 i++;
610             }
611             else
612                 break;
613         }
614     if (ptr && ptr->type == XML_ELEMENT_NODE)
615     {
616         if (!xmlStrcmp(ptr->name, BAD_CAST "term"))
617         {        
618             /* deal with term */
619             yaz_xml2query_term(ptr, &(*zapt)->term, odr, error_code, addinfo);
620         }
621         else
622         {
623             *error_code = 1;
624             *addinfo = "bad element in apt content";
625         }
626     }
627     else
628     {
629         *error_code = 1;
630         *addinfo = "missing term node in apt content";
631     }
632 }
633
634 void yaz_xml2query_rset(const xmlNode *ptr, Z_ResultSetId **rset,
635                         ODR odr, int *error_code, const char **addinfo)
636 {
637     if (ptr->children)
638     {
639         *rset = strVal(ptr->children, odr);
640     }
641     else
642     {
643         *error_code = 1;
644         *addinfo = "missing rset content";
645     }
646 }
647
648 void yaz_xml2query_rpnstructure(const xmlNode *ptr, Z_RPNStructure **zs,
649                                 ODR odr, int *error_code, const char **addinfo)
650 {
651     while (ptr && ptr->type != XML_ELEMENT_NODE)
652         ptr = ptr->next;
653     
654     if (!ptr || ptr->type != XML_ELEMENT_NODE)
655     {
656         *error_code = 1;
657         *addinfo = "missing rpn operator, rset, apt node";
658         return;
659     }
660     *zs = (Z_RPNStructure *) odr_malloc(odr, sizeof(Z_RPNStructure));
661     if (!xmlStrcmp(ptr->name, BAD_CAST "operator"))
662     {
663         Z_Complex *zc = odr_malloc(odr, sizeof(Z_Complex));
664         
665         (*zs)->which = Z_RPNStructure_complex;
666         (*zs)->u.complex = zc;
667         
668         yaz_xml2query_operator(ptr, &zc->roperator, odr, error_code, addinfo);
669
670         ptr = ptr->children;
671         while (ptr && ptr->type != XML_ELEMENT_NODE)
672             ptr = ptr->next;
673         yaz_xml2query_rpnstructure(ptr, &zc->s1, odr, error_code, addinfo);
674         if (ptr)
675             ptr = ptr->next;
676         while (ptr && ptr->type != XML_ELEMENT_NODE)
677             ptr = ptr->next;
678         yaz_xml2query_rpnstructure(ptr, &zc->s2, odr, error_code, addinfo);
679     }
680     else 
681     {
682         Z_Operand *s = (Z_Operand *) odr_malloc(odr, sizeof(Z_Operand));
683         (*zs)->which = Z_RPNStructure_simple;
684         (*zs)->u.simple = s;
685         if (!xmlStrcmp(ptr->name, BAD_CAST "apt"))
686         {
687             s->which = Z_Operand_APT;
688             yaz_xml2query_apt(ptr, &s->u.attributesPlusTerm,
689                               odr, error_code, addinfo);
690         }
691         else if (!xmlStrcmp(ptr->name, BAD_CAST "rset"))
692         {
693             s->which = Z_Operand_resultSetId; 
694             yaz_xml2query_rset(ptr, &s->u.resultSetId,
695                                odr, error_code, addinfo);
696         }
697         else
698         {
699             *error_code = 1;
700             *addinfo = "bad element: expected binary, apt or rset";
701         }        
702     }
703 }
704
705 void yaz_xml2query_rpn(const xmlNode *ptr, Z_RPNQuery **query, ODR odr,
706                    int *error_code, const char **addinfo)
707 {
708     const char *set = (const char *)
709         xmlGetProp((xmlNodePtr) ptr, BAD_CAST "set");
710
711     *query = (Z_RPNQuery*) odr_malloc(odr, sizeof(Z_RPNQuery));
712     if (set)
713         (*query)->attributeSetId = yaz_str_to_z3950oid(odr, CLASS_ATTSET, set);
714     else
715         (*query)->attributeSetId = 0;
716     yaz_xml2query_rpnstructure(ptr->children, &(*query)->RPNStructure,
717                                odr, error_code, addinfo);
718 }
719
720 static void yaz_xml2query_(const xmlNode *ptr, Z_Query **query, ODR odr,
721                            int *error_code, const char **addinfo)
722 {
723     if (ptr && ptr->type == XML_ELEMENT_NODE && 
724         !xmlStrcmp(ptr->name, BAD_CAST "query"))
725     {
726         const char *type;
727         ptr = ptr->children;
728         while (ptr && ptr->type != XML_ELEMENT_NODE)
729             ptr = ptr->next;
730         if (!ptr || ptr->type != XML_ELEMENT_NODE)
731         {
732             *error_code = 1;
733             *addinfo = "missing query content";
734             return;
735         }
736         type = (const char *) ptr->name;
737
738         *query = (Z_Query*) odr_malloc(odr, sizeof(Z_Query));
739         if (!type || !strcmp(type, "rpn"))
740         {
741             (*query)->which = Z_Query_type_1;
742             yaz_xml2query_rpn(ptr, &(*query)->u.type_1, odr,
743                               error_code, addinfo);
744         }
745         else if (!strcmp(type, "ccl"))
746         {
747             *error_code = 1;
748             *addinfo = "ccl not supported yet";
749         }
750         else if (!strcmp(type, "z39.58"))
751         {
752             *error_code = 1;
753             *addinfo = "z39.58 not supported yet";
754         }
755         else if (!strcmp(type, "cql"))
756         {
757             *error_code = 1;
758             *addinfo = "cql not supported yet";
759         }
760         else
761         {
762             *error_code = 1;
763             *addinfo = "unsupported query type";
764         }
765     }
766     else
767     {
768         *error_code = 1;
769         *addinfo = "missing query element";
770     }
771 }
772
773 void yaz_xml2query(const void *xmlnodep, Z_Query **query, ODR odr,
774                    int *error_code, const char **addinfo)
775 {
776     yaz_xml2query_(xmlnodep, query, odr, error_code, addinfo);
777 }
778
779 /* YAZ_HAVE_XML2 */
780 #endif
781
782 /*
783  * Local variables:
784  * c-basic-offset: 4
785  * indent-tabs-mode: nil
786  * End:
787  * vim: shiftwidth=4 tabstop=8 expandtab
788  */