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