12f6daac352ff09a8c6effce212ac937649f1d66
[pazpar2-moved-to-github.git] / src / zeerex.c
1 /* $Id: zeerex.c,v 1.5 2007-03-29 11:02:04 marc Exp $ */
2
3 // Reads Zeerex records into a set of structures
4
5 #include <string.h>
6
7 #include <yaz/yaz-util.h>
8
9 #include <libxml/parser.h>
10 #include <libxml/tree.h>
11
12 #include "zeerex.h"
13
14 // Replace this with something that will take a callback
15 static void fail(const char *s, xmlNode *n)
16 {
17     yaz_log(YLOG_WARN, "Zeerex Err '%s'; elem '%s/%s'", s, n->parent->name, n->name);
18 }
19
20 // returns an nmem-allocated string if attr is present, or null
21 static char *attrtostr(NMEM m, xmlNode *n, const char *name)
22 {
23     char *s = (char *) xmlGetProp(n, (xmlChar *) name);
24     if (s)
25     {
26         char *r = nmem_strdup(m, s);
27         xmlFree(s);
28         return r;
29     }
30     else
31         return 0;
32 }
33
34 static int attrtoint(xmlNode *n, const char *name)
35 {
36     char *s = (char *)xmlGetProp(n, (xmlChar *) name);
37     if (s)
38     {
39         int val = atoi(s);
40         xmlFree(s);
41         return val;
42     }
43     else
44         return 0;
45 }
46
47 static Zr_bool attrtobool(xmlNode *node, const char *name)
48 {
49     char *v = (char *) xmlGetProp(node, (xmlChar *) name);
50     if (v)
51     {
52         Zr_bool res;
53         if (!strcmp(v, "true"))
54             res = Zr_bool_true;
55         else if (!strcmp(v, "false"))
56             res = Zr_bool_false;
57         else
58             res = Zr_bool_unknown;
59         xmlFree(v);
60         return res;
61     }
62     else
63         return Zr_bool_unknown;
64 }
65
66 static char *valuetostr(NMEM m, xmlNode *n)
67 {
68     char *val = (char *) xmlNodeGetContent(n);
69     if (val)
70     {
71         char *res = nmem_strdup(m, val);
72         xmlFree(val);
73         return res;
74     }
75     else
76         return 0;
77 }
78
79 static int valuetoint(xmlNode *n)
80 {
81     char *s = (char *) xmlNodeGetContent(n);
82     if (s)
83     {
84         int res = atoi(s);
85         xmlFree(s);
86         return res;
87     }
88     else
89         return 0;
90 }
91
92 static Zr_langstr *findlangstr(NMEM m, xmlNode *node, const char *name)
93 {
94     xmlNode *n;
95     Zr_langstr *res = 0;
96     for (n = node->children; n; n = n->next)
97     {
98         if (n->type == XML_ELEMENT_NODE 
99             && !strcmp((const char *) n->name, name))
100         {
101             Zr_langstr *new = nmem_malloc(m, sizeof(*new));
102             memset(new, 0, sizeof(*new));
103             new->primary = attrtobool(n, "primary");
104             new->lang = attrtostr(m, n, "lang");
105             new->str = valuetostr(m, n);
106             new->next = res;
107             res = new;
108         }
109     }
110     return res;
111 }
112
113 const char *zr_langstr(Zr_langstr *s, const char *lang)
114 {
115     Zr_langstr *p;
116     for (p = s; p; p = p->next)
117         if ((!lang && p->primary == Zr_bool_true) ||
118                 (lang && p->lang && !strcmp(lang, p->lang)))
119             return p->str;
120     return s->str;
121 }
122
123 static struct zr_authentication *authentication(NMEM m, xmlNode *node)
124 {
125     xmlNode *n;
126     struct zr_authentication *r = nmem_malloc(m, sizeof(*r));
127     memset(r, 0, sizeof(*r));
128     r->type = attrtostr(m, node, "type");
129     for (n = node->children; n; n = n->next)
130     {
131         if (n->type != XML_ELEMENT_NODE)
132             continue;
133         if (!strcmp((const char *) n->name, "open"))
134             r->open = valuetostr(m, n);
135         else if (!strcmp((const char *) n->name, "user"))
136             r->user = valuetostr(m, n);
137         else if (!strcmp((const char *) n->name, "group"))
138             r->group = valuetostr(m, n);
139         else if (!strcmp((const char *) n->name, "password"))
140             r->password = valuetostr(m, n);
141         else
142         {
143             fail("Unexpected element", n);
144             return 0;
145         }
146     }
147     return r;
148 }
149
150
151 static struct zr_serverInfo *serverInfo(NMEM m, xmlNode *node)
152 {
153     xmlNode *n;
154     struct zr_serverInfo *r = nmem_malloc(m, sizeof(*r));
155     memset(r, 0, sizeof(*r));
156
157     r->protocol = attrtostr(m, node, "protocol");
158     r->version = attrtostr(m, node, "version");
159     r->transport = attrtostr(m, node, "transport");
160     r->method = attrtostr(m, node, "method");
161     for (n = node->children; n; n = n->next)
162     {
163         if (n->type != XML_ELEMENT_NODE)
164             continue;
165         if (!strcmp((const char *) n->name, "host"))
166             r->host = valuetostr(m, n);
167         else if (!strcmp((const char *) n->name, "port"))
168             r->port = valuetoint(n);
169         else if (!strcmp((const char *) n->name, "database"))
170             r->database = valuetostr(m, n);
171         else if (!strcmp((const char *) n->name, "authentication"))
172         {
173             if (!(r->authentication = authentication(m, n)))
174                 return 0;
175         }
176         else
177         {
178             fail("Unexpected element", n);
179             return 0;
180         }
181     }
182     return r;
183 }
184
185 static struct zr_agent *agent(NMEM m, xmlNode *node)
186 {
187     struct zr_agent *r = nmem_malloc(m, sizeof(*r));
188     memset(r, 0, sizeof(*r));
189     r->type = attrtostr(m, node, "type");
190     r->identifier = attrtostr(m, node, "identifier");
191     r->value = valuetostr(m, node);
192     return r;
193 }
194
195 static struct zr_implementation *implementation(NMEM m, xmlNode *node)
196 {
197     xmlNode *n;
198     struct zr_implementation *r = nmem_malloc(m, sizeof(*r));
199     memset(r, 0, sizeof(*r));
200     r->identifier = attrtostr(m, node, "identifier");
201     r->version = attrtostr(m, node, "version");
202     r->title = findlangstr(m, node, "title");
203     for (n = node->children; n; n = n->next)
204     {
205         if (n->type != XML_ELEMENT_NODE)
206             continue;
207         if (!strcmp((const char *) n->name, "agent"))
208         {
209             struct zr_agent *ag = agent(m, node);
210             if (!ag)
211                 return 0;
212             ag->next = r->agents;
213             r->agents = ag;
214         }
215     }
216     return r;
217 }
218
219 struct zr_databaseInfo *databaseInfo(NMEM m, xmlNode *node)
220 {
221     xmlNode *n;
222     struct zr_databaseInfo *r = nmem_malloc(m, sizeof(*r));
223     memset(r, 0, sizeof(*r));
224
225     r->title = findlangstr(m, node, "title");
226     r->description = findlangstr(m, node, "description");
227     r->history = findlangstr(m, node, "history");
228     r->extent = findlangstr(m, node, "extent");
229     r->restrictions = findlangstr(m, node, "restrictions");
230     r->langUsage = findlangstr(m, node, "langUsage");
231
232     for (n = node->children; n; n = n->next)
233     {
234         if (n->type != XML_ELEMENT_NODE)
235             continue;
236         if (!strcmp((const char *) n->name, "agents"))
237         {
238             xmlNode *n2;
239             for (n2 = n->children; n2; n2 = n2->next)
240             {
241                 if (n2->type != XML_ELEMENT_NODE)
242                     continue;
243                 if (strcmp((const char *) n2->name, "agent"))
244                     continue;
245                 else
246                 {
247                     struct zr_agent *ag = agent(m, n2);
248                     if (!ag)
249                         return 0;
250                     ag->next = r->agents;
251                     r->agents = ag;
252                 }
253             }
254         }
255         else if (!strcmp((const char *) n->name, "implementation")) 
256         {
257             if (!(r->implementation = implementation(m, n)))
258                 return 0;
259         }
260         else if (!strcmp((const char *) n->name, "links"))
261         {
262             xmlNode *n2;
263             for (n2 = n->children; n2; n2 = n2->next)
264             {
265                 if (n2->type != XML_ELEMENT_NODE)
266                     continue;
267                 if (!strcmp((const char *) n2->name, "link"))
268                     continue;
269                 else
270                 {
271                     struct zr_link *li = nmem_malloc(m, sizeof(*li));
272                     memset(li, 0, sizeof(*li));
273                     li->type = attrtostr(m, n2, "type");
274                     li->value = valuetostr(m, n2);
275                     li->next = r->links;
276                     r->links = li;
277                 }
278             }
279         }
280         else if (!strcmp((const char *) n->name, "history") && !r->lastUpdate)
281             r->lastUpdate = attrtostr(m, n, "lastUpdate");
282         else if (!strcmp((const char *) n->name, "extent") && !r->numberOfRecords)
283             r->numberOfRecords = attrtoint(n, "numberOfRecords");
284         else if (!strcmp((const char *) n->name, "langUsage") && !r->codes)
285             r->codes = attrtostr(m, n, "codes");
286     }
287     return r;
288 }
289
290 struct zr_metaInfo *metaInfo(NMEM m, xmlNode *node)
291 {
292     xmlNode *n;
293     struct zr_metaInfo *r = nmem_malloc(m, sizeof(*r));
294     memset(r, 0, sizeof(*r));
295
296     for (n = node->children; n; n = n->next)
297     {
298         if (n->type != XML_ELEMENT_NODE)
299             continue;
300         if (!strcmp((const char *) n->name, "dateModified"))
301             r->dateModified = valuetostr(m, n);
302         else if (!strcmp((const char *) n->name, "dateAggregated"))
303             r->dateAggregated = valuetostr(m, n);
304         else if (!strcmp((const char *) n->name, "aggregatedFrom"))
305             r->aggregatedFrom = valuetostr(m, n);
306         else
307         {
308             fail("Unexpected element", n);
309             return 0;
310         }
311     }
312     return r;
313 }
314
315 struct zr_set *set(NMEM m, xmlNode *node)
316 {
317     struct zr_set *r = nmem_malloc(m, sizeof(*r));
318     memset(r, 0, sizeof(*r));
319     r->name = attrtostr(m, node, "name");
320     r->identifier = attrtostr(m, node, "identifier");
321     r->title = findlangstr(m, node, "title");
322     return r;
323 }
324
325 struct zr_attr *attr(NMEM m, xmlNode *node)
326 {
327     struct zr_attr *r = nmem_malloc(m, sizeof(*r));
328     memset(r, 0, sizeof(*r));
329     r->type = attrtoint(node, "type");
330     r->set = attrtostr(m, node, "set");
331     return r;
332 }
333
334 static struct zr_map *map(NMEM m, xmlNode *node)
335 {
336     xmlNode *n;
337     struct zr_map *r = nmem_malloc(m, sizeof(*r));
338     memset(r, 0, sizeof(*r));
339
340     r->lang = attrtostr(m, node, "lang");
341     r->primary = attrtobool(node, "primary");
342     for (n = node->children; n; n = n->next)
343     {
344         if (n->type != XML_ELEMENT_NODE)
345             continue;
346         if (!strcmp((const char *) n->name, "name"))
347         {
348             r->set = attrtostr(m, n, "set");
349             r->name = valuetostr(m, n);
350         }
351         else if (!strcmp((const char *) n->name, "attr"))
352         {
353             struct zr_attr *new = attr(m, n);
354             if (!new)
355                 return 0;
356             new->next = r->attrs;
357             r->attrs = new;
358         }
359         else
360         {
361             fail("Unexpected element", n);
362             return 0;
363         }
364     }
365     return r;
366 }
367
368 static Zr_setting *findsetting(NMEM m, xmlNode *node, char *name)
369 {
370     static Zr_setting *r = 0;
371     xmlNode *n;
372     for (n = node->children; n; n = n->next)
373     {
374         if (node->type == XML_ELEMENT_NODE && !strcmp((const char *) n->name, name))
375         {
376             xmlNode *n2;
377             struct zr_setting *new = nmem_malloc(m, sizeof(*new));
378             memset(new, 0, sizeof(*new));
379             new->type = attrtostr(m, n, "type");
380             for (n2 = n->children; n2; n2 = n2->next)
381             {
382                 if (n2->type == XML_ELEMENT_NODE && !strcmp((const char *) n2->name, "map"))
383                 {
384                     new->map = map(m, n2);
385                     if (!new)
386                         return 0;
387                     break;
388                 }
389             }
390             if (!new->map)
391                 new->value = (char *) xmlNodeGetContent(n);
392             new->next = r;
393             r = new;
394         }
395     }
396     return r;
397 }
398
399 static struct zr_configInfo *configInfo(NMEM m, xmlNode *node)
400 {
401     struct zr_configInfo *r = nmem_malloc(m, sizeof(*r));
402
403     r->defaultv = findsetting(m, node, "default");
404     r->setting = findsetting(m, node, "setting");
405     r->supports = findsetting(m, node, "supports");
406     return r;
407 }
408
409 static struct zr_index *parse_index(NMEM m, xmlNode *node)
410 {
411     xmlNode *n;
412     struct zr_index *r = nmem_malloc(m, sizeof(*r));
413     memset(r, 0, sizeof(*r));
414
415     r->search = attrtobool(node, "search");
416     r->scan = attrtobool(node, "scan");
417     r->sort = attrtobool(node, "sort");
418     r->id = attrtostr(m, node, "id");
419     r->title = findlangstr(m, node, "title");
420
421     for (n = node->children; n; n = n->next)
422     {
423         if (n->type != XML_ELEMENT_NODE)
424             continue;
425         if (!strcmp((const char *) n->name, "map"))
426         {
427             struct zr_map *new = map(m, n);
428             if (!new)
429                 return 0;
430             new->next = r->maps;
431             r->maps = new;
432         }
433         else if (!strcmp((const char *) n->name, "configInfo"))
434         {
435             if (!(r->configInfo = configInfo(m, n)))
436                 return 0;
437         }
438         else if (strcmp((const char *) n->name, "title"))
439         {
440             fail("Unknown child element", n);
441             return 0;
442         }
443     }
444     return r;
445 }
446
447 static struct zr_sortKeyword *sortKeyword(NMEM m, xmlNode *node)
448 {
449     struct zr_sortKeyword *r = nmem_malloc(m, sizeof(*r));
450     memset(r, 0, sizeof(*r));
451     r->value = valuetostr(m, node);
452     return r;
453 }
454
455 static struct zr_indexInfo *indexInfo(NMEM m , xmlNode *node)
456 {
457     xmlNode *n;
458     struct zr_indexInfo *r = nmem_malloc(m, sizeof(*r));
459     memset(r, 0, sizeof(*r));
460
461     for (n = node->children; n; n = n->next)
462     {
463         if (n->type != XML_ELEMENT_NODE)
464             continue;
465         if (!strcmp((const char *) n->name, "set"))
466         {
467             struct zr_set *new = set(m, n);
468             if (!new)
469                 return 0;
470             new->next = r->sets;
471             r->sets = new;
472         }
473         else if (!strcmp((const char *) n->name, "index"))
474         {
475             struct zr_index *new = parse_index(m, n);
476             if (!new)
477                 return 0;
478             new->next = r->indexes;
479             r->indexes = new;
480         }
481         else if (!strcmp((const char *) n->name, "sortKeyword"))
482         {
483             struct zr_sortKeyword *new = sortKeyword(m, n);
484             if (!new)
485                 return 0;
486             new->next = r->sortKeywords;
487             r->sortKeywords = new;
488         }
489         else if (!strcmp((const char *) n->name, "sortKeyword"))
490         {
491             if (!(r->configInfo = configInfo(m, n)))
492                 return 0;
493         }
494         else
495         {
496             fail("Unknown child element", n);
497             return 0;
498         }
499     }
500     return r;
501 }
502
503 static struct zr_elementSet *elementSet(NMEM m, xmlNode *node)
504 {
505     struct zr_elementSet *r = nmem_malloc(m, sizeof(*r));
506     memset(r, 0, sizeof(*r));
507     r->name = attrtostr(m, node, "name");
508     r->identifier = attrtostr(m, node, "identifier");
509     r->title = findlangstr(m, node, "title");
510     return r;
511 }
512
513 static struct zr_recordSyntax *recordSyntax(NMEM m, xmlNode *node)
514 {
515     xmlNode *n;
516     struct zr_recordSyntax *r = nmem_malloc(m, sizeof(*r));
517     struct zr_elementSet **elementp = &r->elementSets;
518
519     memset(r, 0, sizeof(*r));
520     r->name = attrtostr(m, node, "name");
521     r->identifier = attrtostr(m, node, "identifier");
522     for (n = node->children; n; n = n->next)
523     {
524         if (n->type != XML_ELEMENT_NODE)
525             continue;
526         if (!strcmp((const char *) n->name, "elementSet"))
527         {
528             if (!(*elementp = elementSet(m, n)))
529                 return 0;
530             elementp = &(*elementp)->next;
531         }
532         else
533         {
534             fail("Unknown child element", n);
535             return 0;
536         }
537     }
538     return r;
539 }
540
541 static struct zr_recordInfo *recordInfo(NMEM m, xmlNode *node)
542 {
543     xmlNode *n;
544     struct zr_recordInfo *r = nmem_malloc(m, sizeof(*r));
545     struct zr_recordSyntax **syntaxp = &r->recordSyntaxes;
546
547     memset(r, 0, sizeof(*r));
548     for (n = node->children; n; n = n->next)
549     {
550         if (n->type != XML_ELEMENT_NODE)
551             continue;
552         if (!strcmp((const char *) n->name, "recordSyntax"))
553         {
554             if (!(*syntaxp = recordSyntax(m, n)))
555                 return 0;
556             syntaxp = &(*syntaxp)->next;
557         }
558         else
559         {
560             fail("Unknown child element", n);
561             return 0;
562         }
563     }
564     return r;
565 }
566
567
568 static struct zr_schema *schema(NMEM m, xmlNode *node)
569 {
570     struct zr_schema *r = nmem_malloc(m, sizeof(*r));
571     memset(r, 0, sizeof(*r));
572     
573     r->name = attrtostr(m, node, "name");
574     r->identifier = attrtostr(m, node, "identifier");
575     r->retrieve = attrtobool(node, "retrieve");
576     r->sort = attrtobool(node, "sort");
577     r->location = attrtostr(m, node, "location");
578     r->title = findlangstr(m, node, "title");
579     return r;
580 }
581
582 static struct zr_schemaInfo *schemaInfo(NMEM m, xmlNode *node)
583 {
584     xmlNode *n;
585     struct zr_schemaInfo *r = nmem_malloc(m, sizeof(*r));
586     struct zr_schema **schemap = &r->schemas;
587
588     memset(r, 0, sizeof(*r));
589     for (n = node->children; n; n = n->next)
590     {
591         if (n->type != XML_ELEMENT_NODE)
592             continue;
593         if (!strcmp((const char *) n->name, "schema"))
594         {
595             if (!(*schemap = schema(m, n)))
596                 return 0;
597             schemap = &(*schemap)->next;
598         }
599         else
600         {
601             fail("Unknown child element", n);
602             return 0;
603         }
604     }
605     return r;
606 }
607
608 static struct zr_explain *explain(NMEM m, xmlNode *node)
609 {
610     xmlNode *n;
611     struct zr_explain *r = nmem_malloc(m, sizeof(*r));
612     memset(r, 0, sizeof(*r));
613
614     for (n = node->children; n; n = n->next)
615     {
616         if (n->type != XML_ELEMENT_NODE)
617             continue;
618         if (!strcmp((const char *) n->name, "serverInfo"))
619         {
620             if (!(r->serverInfo = serverInfo(m, n)))
621                 return 0;
622         }
623         else if (!strcmp((const char *) n->name, "databaseInfo"))
624         {
625             if (!(r->databaseInfo = databaseInfo(m, n)))
626                 return 0;
627         }
628         else if (!strcmp((const char *) n->name, "metaInfo"))
629         {
630             if (!(r->metaInfo = metaInfo(m, n)))
631                 return 0;
632         }
633         else if (!strcmp((const char *) n->name, "indexInfo"))
634         {
635             if (!(r->indexInfo = indexInfo(m, n)))
636                 return 0;
637         }
638         else if (!strcmp((const char *) n->name, "recordInfo"))
639         {
640             if (!(r->recordInfo = recordInfo(m, n)))
641                 return 0;
642         }
643         else if (!strcmp((const char *) n->name, "schemaInfo"))
644         {
645             if (!(r->schemaInfo = schemaInfo(m, n)))
646                 return 0;
647         }
648         else if (!strcmp((const char *) n->name, "configInfo"))
649         {
650             if (!(r->configInfo = configInfo(m, n)))
651                return 0;
652         }
653         else if (!strcmp((const char *) n->name, "status"))
654             continue;
655         else
656         {
657             fail("Unknown child element of root node", n);
658             return 0;
659         }
660     }
661     return r;
662 }
663
664 struct zr_explain *zr_read_xml(NMEM m, xmlNode *n)
665 {
666     return explain(m, n);
667 }
668
669 struct zr_explain *zr_read_file(NMEM m, const char *fn)
670 {
671     xmlDoc *doc = xmlParseFile(fn);
672     struct zr_explain *r;
673     if (!doc)
674     {
675         yaz_log(YLOG_WARN|YLOG_ERRNO, "Unable to open %s", fn);
676         return 0;
677     }
678     r = explain(m, xmlDocGetRootElement(doc));
679     xmlFree(doc);
680     return r;
681 }
682
683 /*
684  * Local variables:
685  * c-basic-offset: 4
686  * indent-tabs-mode: nil
687  * End:
688  * vim: shiftwidth=4 tabstop=8 expandtab
689  */