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