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