Fix leak for odr_print of ZOOM connection.
[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 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 xmlNodePtr yaz_query2xml_term(const Z_Term *term,
121                               xmlNodePtr parent)
122 {
123     xmlNodePtr t = 0;
124     xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "term", 0);
125     char formstr[20];
126     const char *type = 0;
127
128     switch (term->which)
129     {
130     case Z_Term_general:
131         type = "general";
132         t = xmlNewTextLen(BAD_CAST term->u.general->buf, term->u.general->len);
133         break;
134     case Z_Term_numeric:
135         type = "numeric";
136         sprintf(formstr, ODR_INT_PRINTF, *term->u.numeric);
137         t = xmlNewText(BAD_CAST formstr);       
138         break;
139     case Z_Term_characterString:
140         type = "string";
141         t = xmlNewText(BAD_CAST term->u.characterString);
142         break;
143     case Z_Term_oid:
144         type = "oid";
145         break;
146     case Z_Term_dateTime:
147         type = "dateTime";
148         break;
149     case Z_Term_external:
150         type = "external";
151         break;
152     case Z_Term_integerAndUnit:
153         type ="integerAndUnit";
154         break;
155     case Z_Term_null:
156         type = "null";
157         break;
158     default:
159         break;
160     }
161     if (t) /* got a term node ? */
162         xmlAddChild(node, t);
163     if (type)
164         xmlNewProp(node, BAD_CAST "type", BAD_CAST type);
165     return node;
166 }
167
168 xmlNodePtr yaz_query2xml_apt(const Z_AttributesPlusTerm *zapt,
169                              xmlNodePtr parent)
170 {
171     xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "apt", 0);
172     int num_attributes = zapt->attributes->num_attributes;
173     int i;
174     for (i = 0; i<num_attributes; i++)
175         yaz_query2xml_attribute_element(zapt->attributes->attributes[i], node);
176     yaz_query2xml_term(zapt->term, node);
177
178     return node;
179 }
180
181
182 void yaz_query2xml_operator(Z_Operator *op, xmlNodePtr node)
183 {
184     const char *type = 0;
185     switch(op->which)
186     {
187     case Z_Operator_and:
188         type = "and";
189         break;
190     case Z_Operator_or:
191         type = "or";
192         break;
193     case Z_Operator_and_not:
194         type = "not";
195         break;
196     case Z_Operator_prox:
197         type = "prox";
198         break;
199     default:
200         return;
201     }
202     xmlNewProp(node, BAD_CAST "type", BAD_CAST type);
203     
204     if (op->which == Z_Operator_prox)
205     {
206         char formstr[30];
207         
208         if (op->u.prox->exclusion)
209         {
210             if (*op->u.prox->exclusion)
211                 xmlNewProp(node, BAD_CAST "exclusion", BAD_CAST "true");
212             else
213                 xmlNewProp(node, BAD_CAST "exclusion", BAD_CAST "false");
214         }
215         sprintf(formstr, ODR_INT_PRINTF, *op->u.prox->distance);
216         xmlNewProp(node, BAD_CAST "distance", BAD_CAST formstr);
217
218         if (*op->u.prox->ordered)
219             xmlNewProp(node, BAD_CAST "ordered", BAD_CAST "true");
220         else 
221             xmlNewProp(node, BAD_CAST "ordered", BAD_CAST "false");
222        
223         sprintf(formstr, ODR_INT_PRINTF, *op->u.prox->relationType);
224         xmlNewProp(node, BAD_CAST "relationType", BAD_CAST formstr);
225         
226         switch(op->u.prox->which)
227         {
228         case Z_ProximityOperator_known:
229             sprintf(formstr, ODR_INT_PRINTF, *op->u.prox->u.known);
230             xmlNewProp(node, BAD_CAST "knownProximityUnit",
231                        BAD_CAST formstr);
232             break;
233         case Z_ProximityOperator_private:
234         default:
235             xmlNewProp(node, BAD_CAST "privateProximityUnit",
236                        BAD_CAST "private");
237             break;
238         }
239     }
240 }
241
242 xmlNodePtr yaz_query2xml_rpnstructure(const Z_RPNStructure *zs,
243                                       xmlNodePtr parent)
244 {
245     if (zs->which == Z_RPNStructure_complex)
246     {
247         Z_Complex *zc = zs->u.complex;
248
249         xmlNodePtr node = xmlNewChild(parent, /* NS */ 0, BAD_CAST "operator", 0);
250         if (zc->roperator)
251             yaz_query2xml_operator(zc->roperator, node);
252         yaz_query2xml_rpnstructure(zc->s1, node);
253         yaz_query2xml_rpnstructure(zc->s2, node);
254         return node;
255     }
256     else if (zs->which == Z_RPNStructure_simple)
257     {
258         if (zs->u.simple->which == Z_Operand_APT)
259             return yaz_query2xml_apt(zs->u.simple->u.attributesPlusTerm,
260                                      parent);
261         else if (zs->u.simple->which == Z_Operand_resultSetId)
262             return xmlNewChild(parent, /* NS */ 0, BAD_CAST "rset", 
263                                BAD_CAST zs->u.simple->u.resultSetId);
264     }
265     return 0;
266 }
267
268 xmlNodePtr yaz_query2xml_rpn(const Z_RPNQuery *rpn, xmlNodePtr parent)
269 {
270     if (rpn->attributeSetId)
271     {
272         char oid_name_str[OID_STR_MAX];
273         const char *setname = yaz_oid_to_string_buf(rpn->attributeSetId,
274                                                     0, oid_name_str);
275         if (setname)
276             xmlNewProp(parent, BAD_CAST "set", BAD_CAST setname);
277     }
278     return yaz_query2xml_rpnstructure(rpn->RPNStructure, parent);
279 }
280
281 xmlNodePtr yaz_query2xml_ccl(const Odr_oct *ccl, xmlNodePtr node)
282 {
283     return 0;
284 }
285
286 xmlNodePtr yaz_query2xml_z3958(const Odr_oct *ccl, xmlNodePtr node)
287 {
288     return 0;
289 }
290
291 xmlNodePtr yaz_query2xml_cql(const char *cql, xmlNodePtr node)
292 {
293     return 0;
294 }
295
296 void yaz_rpnquery2xml(const Z_RPNQuery *rpn, xmlDocPtr *docp)
297 {
298     Z_Query query;
299
300     query.which = Z_Query_type_1;
301     query.u.type_1 = (Z_RPNQuery *) rpn;
302     yaz_query2xml(&query, docp);
303 }
304
305 void yaz_query2xml(const Z_Query *q, xmlDocPtr *docp)
306 {
307     xmlNodePtr top_node, q_node = 0, child_node = 0;
308
309     assert(q);
310     assert(docp);
311
312     top_node = xmlNewNode(0, BAD_CAST "query");
313
314     switch (q->which)
315     {
316     case Z_Query_type_1: 
317     case Z_Query_type_101:
318         q_node = xmlNewChild(top_node, 0, BAD_CAST "rpn", 0);
319         child_node = yaz_query2xml_rpn(q->u.type_1, q_node);
320         break;
321     case Z_Query_type_2:
322         q_node = xmlNewChild(top_node, 0, BAD_CAST "ccl", 0);
323         child_node = yaz_query2xml_ccl(q->u.type_2, q_node);
324         break;
325     case Z_Query_type_100:
326         q_node = xmlNewChild(top_node, 0, BAD_CAST "z39.58", 0);
327         child_node = yaz_query2xml_z3958(q->u.type_100, q_node);
328         break;
329     case Z_Query_type_104:
330         if (q->u.type_104->which == Z_External_CQL)
331         {
332             q_node = xmlNewChild(top_node, 0, BAD_CAST "cql", 0);
333             child_node = yaz_query2xml_cql(q->u.type_104->u.cql, q_node);
334         }
335     }
336     if (child_node && q_node)
337     {
338         *docp = xmlNewDoc(BAD_CAST "1.0");
339         xmlDocSetRootElement(*docp, top_node); /* make it top node in doc */
340     }
341     else
342     {
343         *docp = 0;
344         xmlFreeNode(top_node);
345     }
346 }
347
348 bool_t *boolVal(ODR odr, const char *str)
349 {
350     if (*str == '\0' || strchr("0fF", *str))
351         return odr_booldup(odr, 0);
352     return odr_booldup(odr, 1);
353 }
354
355 Odr_int *intVal(ODR odr, const char *str)
356 {
357     return odr_intdup(odr, atoi(str));
358 }
359
360 void yaz_xml2query_operator(const xmlNode *ptr, Z_Operator **op,
361                             ODR odr, 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 void yaz_xml2query_attribute_element(const xmlNode *ptr, 
454                                      Z_AttributeElement **elem, ODR odr,
455                                      int *error_code, const char **addinfo)
456 {
457     int i;
458     xmlChar *set = 0;
459     xmlChar *type = 0;
460     xmlChar *value = 0;
461     int num_values = 0;
462     struct _xmlAttr *attr;
463     for (attr = ptr->properties; attr; attr = attr->next)
464     {
465         if (!xmlStrcmp(attr->name, BAD_CAST "set") &&
466             attr->children && attr->children->type == XML_TEXT_NODE)
467             set = attr->children->content;
468         else if (!xmlStrcmp(attr->name, BAD_CAST "type") &&
469             attr->children && attr->children->type == XML_TEXT_NODE)
470             type = attr->children->content;
471         else if (!xmlStrcmp(attr->name, BAD_CAST "value") &&
472             attr->children && attr->children->type == XML_TEXT_NODE)
473         {
474             value = attr->children->content;
475             num_values++;
476         }
477         else
478         {
479             *error_code = 1;
480             *addinfo = "bad attribute for attr content";
481             return;
482         }
483     }
484     if (!type)
485     {
486         *error_code = 1;
487         *addinfo = "missing type attribute for att content";
488         return;
489     }
490     if (!value)
491     {
492         *error_code = 1;
493         *addinfo = "missing value attribute for att content";
494         return;
495     }
496         
497     *elem = (Z_AttributeElement *) odr_malloc(odr, sizeof(**elem));
498     if (set)
499         (*elem)->attributeSet = yaz_string_to_oid_odr(yaz_oid_std(),
500                                                       CLASS_ATTSET,
501                                                       (const char *) set,
502                                                       odr);
503     else
504         (*elem)->attributeSet = 0;
505     (*elem)->attributeType = intVal(odr, (const char *) type);
506
507     /* looks like a number ? */
508     for (i = 0; value[i] && value[i] >= '0' && value[i] <= '9'; i++)
509         ;
510     if (num_values > 1 || value[i])
511     {   /* multiple values or string, so turn to complex attribute */
512         (*elem)->which = Z_AttributeValue_complex;
513         (*elem)->value.complex =
514             (Z_ComplexAttribute*) odr_malloc(odr, sizeof(Z_ComplexAttribute));
515         (*elem)->value.complex->num_list = num_values;
516         (*elem)->value.complex->list = (Z_StringOrNumeric **)
517             odr_malloc(odr, sizeof(Z_StringOrNumeric*) * num_values);
518
519         /* second pass over attr values */
520         i = 0;
521         for (attr = ptr->properties; attr; attr = attr->next)
522         {
523             if (!xmlStrcmp(attr->name, BAD_CAST "value") &&
524                 attr->children && attr->children->type == XML_TEXT_NODE)
525             {
526                 const char *val = (const char *) attr->children->content;
527                 assert (i < num_values);
528                 (*elem)->value.complex->list[i] = (Z_StringOrNumeric *)
529                     odr_malloc(odr, sizeof(Z_StringOrNumeric));
530                 (*elem)->value.complex->list[i]->which =
531                     Z_StringOrNumeric_string;
532                 (*elem)->value.complex->list[i]->u.string =
533                     odr_strdup(odr, val);
534                 i++;
535             }
536         }
537         (*elem)->value.complex->num_semanticAction = 0;
538         (*elem)->value.complex->semanticAction = 0;        
539     }
540     else
541     {   /* good'ld numeric value */
542         (*elem)->which = Z_AttributeValue_numeric;
543         (*elem)->value.numeric = intVal(odr, (const char *) value);
544     }
545 }
546
547 char *strVal(const xmlNode *ptr_cdata, ODR odr)
548 {
549     return nmem_text_node_cdata(ptr_cdata, odr_getmem(odr));
550 }
551
552 void yaz_xml2query_term(const xmlNode *ptr,
553                        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 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 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 void yaz_xml2query_rpnstructure(const xmlNode *ptr, Z_RPNStructure **zs,
699                                 ODR odr, int *error_code, const char **addinfo)
700 {
701     while (ptr && ptr->type != XML_ELEMENT_NODE)
702         ptr = ptr->next;
703     
704     if (!ptr || ptr->type != XML_ELEMENT_NODE)
705     {
706         *error_code = 1;
707         *addinfo = "missing rpn operator, rset, apt node";
708         return;
709     }
710     if (check_diagnostic(ptr, odr, error_code, addinfo))
711         return;
712
713     *zs = (Z_RPNStructure *) odr_malloc(odr, sizeof(Z_RPNStructure));
714     if (!xmlStrcmp(ptr->name, BAD_CAST "operator"))
715     {
716         Z_Complex *zc = (Z_Complex *) odr_malloc(odr, sizeof(Z_Complex));
717         
718         (*zs)->which = Z_RPNStructure_complex;
719         (*zs)->u.complex = zc;
720         
721         yaz_xml2query_operator(ptr, &zc->roperator, odr, error_code, addinfo);
722
723         ptr = ptr->children;
724         while (ptr && ptr->type != XML_ELEMENT_NODE)
725             ptr = ptr->next;
726         yaz_xml2query_rpnstructure(ptr, &zc->s1, odr, error_code, addinfo);
727         if (ptr)
728             ptr = ptr->next;
729         while (ptr && ptr->type != XML_ELEMENT_NODE)
730             ptr = ptr->next;
731         yaz_xml2query_rpnstructure(ptr, &zc->s2, odr, error_code, addinfo);
732     }
733     else 
734     {
735         Z_Operand *s = (Z_Operand *) odr_malloc(odr, sizeof(Z_Operand));
736         (*zs)->which = Z_RPNStructure_simple;
737         (*zs)->u.simple = s;
738         if (!xmlStrcmp(ptr->name, BAD_CAST "apt"))
739         {
740             s->which = Z_Operand_APT;
741             yaz_xml2query_apt(ptr, &s->u.attributesPlusTerm,
742                               odr, error_code, addinfo);
743         }
744         else if (!xmlStrcmp(ptr->name, BAD_CAST "rset"))
745         {
746             s->which = Z_Operand_resultSetId; 
747             yaz_xml2query_rset(ptr, &s->u.resultSetId,
748                                odr, error_code, addinfo);
749         }
750         else
751         {
752             *error_code = 1;
753             *addinfo = "bad element: expected binary, apt or rset";
754         }        
755     }
756 }
757
758 void yaz_xml2query_rpn(const xmlNode *ptr, Z_RPNQuery **query, ODR odr,
759                    int *error_code, const char **addinfo)
760 {
761     const char *set = (const char *)
762         xmlGetProp((xmlNodePtr) ptr, BAD_CAST "set");
763
764     *query = (Z_RPNQuery*) odr_malloc(odr, sizeof(Z_RPNQuery));
765     if (set)
766         (*query)->attributeSetId = yaz_string_to_oid_odr(yaz_oid_std(),
767                                                          CLASS_ATTSET, set, odr);
768     else
769         (*query)->attributeSetId = 0;
770     yaz_xml2query_rpnstructure(ptr->children, &(*query)->RPNStructure,
771                                odr, error_code, addinfo);
772 }
773
774 static void yaz_xml2query_(const xmlNode *ptr, Z_Query **query, ODR odr,
775                            int *error_code, const char **addinfo)
776 {
777     if (check_diagnostic(ptr, odr, error_code, addinfo))
778         return;
779     if (ptr && ptr->type == XML_ELEMENT_NODE && 
780         !xmlStrcmp(ptr->name, BAD_CAST "query"))
781     {
782         const char *type;
783         ptr = ptr->children;
784         while (ptr && ptr->type != XML_ELEMENT_NODE)
785             ptr = ptr->next;
786         if (!ptr || ptr->type != XML_ELEMENT_NODE)
787         {
788             *error_code = 1;
789             *addinfo = "missing query content";
790             return;
791         }
792         type = (const char *) ptr->name;
793
794         *query = (Z_Query*) odr_malloc(odr, sizeof(Z_Query));
795         if (!type || !strcmp(type, "rpn"))
796         {
797             (*query)->which = Z_Query_type_1;
798             yaz_xml2query_rpn(ptr, &(*query)->u.type_1, odr,
799                               error_code, addinfo);
800         }
801         else if (!strcmp(type, "ccl"))
802         {
803             *error_code = 1;
804             *addinfo = "ccl not supported yet";
805         }
806         else if (!strcmp(type, "z39.58"))
807         {
808             *error_code = 1;
809             *addinfo = "z39.58 not supported yet";
810         }
811         else if (!strcmp(type, "cql"))
812         {
813             *error_code = 1;
814             *addinfo = "cql not supported yet";
815         }
816         else
817         {
818             *error_code = 1;
819             *addinfo = "unsupported query type";
820         }
821     }
822     else
823     {
824         *error_code = 1;
825         *addinfo = "missing query element";
826     }
827 }
828
829 void yaz_xml2query(const xmlNode *xmlnodep, Z_Query **query, ODR odr,
830                    int *error_code, const char **addinfo)
831 {
832     yaz_xml2query_(xmlnodep, query, odr, error_code, addinfo);
833 }
834
835 /* YAZ_HAVE_XML2 */
836 #endif
837
838 /*
839  * Local variables:
840  * c-basic-offset: 4
841  * c-file-style: "Stroustrup"
842  * indent-tabs-mode: nil
843  * End:
844  * vim: shiftwidth=4 tabstop=8 expandtab
845  */
846