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