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