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