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