First stab at a marc map as a fast alternat to XSLT
[pazpar2-moved-to-github.git] / src / marcmap.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4
5 #include <libxml/parser.h>
6 #include <libxml/tree.h>
7
8 #include <yaz/nmem.h>
9
10 #include <marcmap.h>
11 #include <marchash.h>
12
13 struct marcmap *marcmap_load(char *filename, NMEM nmem) {
14     struct marcmap *mm;
15     struct marcmap *mmhead;
16     FILE *fp;
17     char c;
18     char buf[256];
19     int len;
20     int field;
21     int newrec;
22
23     len = 0;
24     field = 0;
25     newrec = 1;
26     mm = NULL;
27     mmhead = NULL;
28     fp = fopen(filename, "r");
29
30     while ((c = getc(fp) ) != EOF) 
31     {
32         // allocate some space
33         if (newrec)
34         {
35             if (mm != NULL) 
36             {
37                 mm->next = nmem_malloc(nmem, sizeof(struct marcmap));
38                 mm = mm->next;
39             }
40             // first one!
41             else 
42             { mm = nmem_malloc(nmem, sizeof(struct marcmap));
43                 mmhead = mm;
44             }
45             newrec = 0;
46         }
47         // whitespace saves and moves on
48         if (c == ' ' || c == '\n' || c == '\t')
49         {
50             buf[len] = '\0';
51             len++;
52             // first field, marc
53             if (field == 0)
54             {
55                 // allow blank lines
56                 if (!(len <3))
57                 {
58                     mm->field = nmem_malloc(nmem, len * sizeof(char));
59                     strncpy(mm->field, buf, len);
60                 }
61             }
62             // second, marc subfield, just a char
63             else if (field == 1)
64             {
65                 mm->subfield = buf[len-2];
66             }
67             // third, pz fieldname
68             else if (field == 2) 
69             { 
70                 mm->pz = nmem_malloc(nmem, len * sizeof(char));
71                 strncpy(mm->pz, buf, len);
72             }
73
74             // new line, new record
75             if (c == '\n')
76             {
77                 field = 0;
78                 newrec = 1;
79             }
80             else
81             {
82                 field++;
83             }
84             len = 0;
85         }
86         else
87         {
88             buf[len] = c;
89             len++;
90         }
91     }
92     mm->next = NULL;
93     return mmhead;
94 }
95
96 xmlDoc *marcmap_apply(struct marcmap *marcmap, xmlDoc *xml_in)
97 {
98     char mergekey[1024];
99     char medium[32];
100     char *s;
101     NMEM nmem;
102     xmlNsPtr ns_pz;
103     xmlDocPtr xml_out;
104     xmlNodePtr xml_out_root;
105     xmlNodePtr rec_node;
106     xmlNodePtr meta_node; 
107     struct marchash *marchash;
108     struct marcfield *field;
109     struct marcsubfield *subfield;
110     struct marcmap *mmcur;
111      
112     xml_out = xmlNewDoc(BAD_CAST "1.0");
113     xml_out_root = xmlNewNode(NULL, BAD_CAST "record");
114     xmlDocSetRootElement(xml_out, xml_out_root);
115     ns_pz = xmlNewNs(xml_out_root, BAD_CAST "http://www.indexdata.com/pazpar2/1.0", BAD_CAST "pz"); 
116     nmem = nmem_create();
117     rec_node = xmlDocGetRootElement(xml_in);
118     marchash = marchash_create(nmem);
119     marchash_ingest_marcxml(marchash, rec_node);
120
121     mmcur = marcmap;
122     while (mmcur != NULL)
123     {
124         if (field = marchash_get_field(marchash, mmcur->field, NULL))
125             do
126             {
127                 // field value
128                 if ((mmcur->subfield == '$') && (s = field->val))
129                 {
130                     meta_node = xmlNewChild(xml_out_root, ns_pz, BAD_CAST "metadata", s);
131                     xmlSetProp(meta_node, BAD_CAST "type", mmcur->pz); 
132                 }
133                 // catenate all subfields
134                 else if ((mmcur->subfield == '*') && (s = marchash_catenate_subfields(field, " ", nmem)))
135                 {
136                     meta_node = xmlNewChild(xml_out_root, ns_pz, BAD_CAST "metadata", s);
137                     xmlSetProp(meta_node, BAD_CAST "type", mmcur->pz);
138                 }
139                 // subfield value
140                 else if (mmcur->subfield) 
141                 {
142                     if (subfield = marchash_get_subfield(mmcur->subfield, field, NULL)) 
143                         do
144                             if (s = subfield->val)
145                             {
146                                 meta_node = xmlNewChild(xml_out_root, ns_pz, BAD_CAST "metadata", s);
147                                 xmlSetProp(meta_node, BAD_CAST "type", mmcur->pz);
148                             }
149                         while (subfield = marchash_get_subfield(mmcur->subfield, field, subfield));
150                 }
151                 
152             }
153             while (field = marchash_get_field(marchash, mmcur->field, field));
154         mmcur = mmcur->next;
155     }
156
157     // hard coded mappings
158
159     // medium
160     if ((field = marchash_get_field(marchash, "245", NULL)) && (subfield = marchash_get_subfield('h', field, NULL)))
161     {
162        strncpy(medium, subfield->val, 32);
163     }
164     else if ((field = marchash_get_field(marchash, "900", NULL)) && (subfield = marchash_get_subfield('a', field, NULL)))
165        strcpy(medium, "electronic resource");
166     else if ((field = marchash_get_field(marchash, "900", NULL)) && (subfield = marchash_get_subfield('b', field, NULL)))
167        strcpy(medium, "electronic resource");
168     else if ((field = marchash_get_field(marchash, "773", NULL)) && (subfield = marchash_get_subfield('t', field, NULL)))
169        strcpy(medium, "article");
170     else
171        strcpy(medium, "book");
172
173     meta_node = xmlNewChild(xml_out_root, ns_pz, BAD_CAST "metadata", BAD_CAST medium);
174     xmlSetProp(meta_node, BAD_CAST "type", BAD_CAST "medium");
175
176     // merge key
177     memset(mergekey, 0, 1024);
178     strcpy(mergekey, "title ");
179     if ((field = marchash_get_field(marchash, "245", NULL)) && (subfield = marchash_get_subfield('a', field, NULL)))
180         strncat(mergekey, subfield->val, 1023 - strlen(mergekey));
181     strncat(mergekey, " author ", 1023 - strlen(mergekey));
182     if ((field = marchash_get_field(marchash, "245", NULL)) && (subfield = marchash_get_subfield('a', field, NULL)))
183         strncat(mergekey, subfield->val, 1023 - strlen(mergekey));
184     strncat(mergekey, " medium ", 1023 - strlen(mergekey));
185     strncat(mergekey, medium, 1023 - strlen(mergekey));
186
187     xmlSetProp(xml_out_root, BAD_CAST "mergekey", BAD_CAST mergekey);
188
189     nmem_destroy(nmem);
190     return xml_out;
191 }