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