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