Mods for Windows compilation
[pazpar2-moved-to-github.git] / src / marcmap.c
1 /* This file is part of Pazpar2.
2    Copyright (C) 2006-2009 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 /** \file
21     \brief MARC map implementation
22 */
23
24 #if HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31
32 #include <libxml/parser.h>
33 #include <libxml/tree.h>
34
35 #include <yaz/nmem.h>
36
37 #include "marcmap.h"
38 #include "marchash.h"
39
40 struct marcmap *marcmap_load(char *filename, NMEM nmem) {
41     struct marcmap *mm;
42     struct marcmap *mmhead;
43     FILE *fp;
44     char c;
45     char buf[256];
46     int len;
47     int field;
48     int newrec;
49
50     len = 0;
51     field = 0;
52     newrec = 1;
53     mm = NULL;
54     mmhead = NULL;
55     fp = fopen(filename, "r");
56
57     while ((c = getc(fp) ) != EOF) 
58     {
59         // allocate some space
60         if (newrec)
61         {
62             if (mm != NULL) 
63             {
64                 mm->next = nmem_malloc(nmem, sizeof(struct marcmap));
65                 mm = mm->next;
66             }
67             // first one!
68             else 
69             { mm = nmem_malloc(nmem, sizeof(struct marcmap));
70                 mmhead = mm;
71             }
72             newrec = 0;
73         }
74         // whitespace saves and moves on
75         if (c == ' ' || c == '\n' || c == '\t')
76         {
77             buf[len] = '\0';
78             len++;
79             // first field, marc
80             if (field == 0)
81             {
82                 // allow blank lines
83                 if (!(len <3))
84                 {
85                     mm->field = nmem_malloc(nmem, len * sizeof(char));
86                     strncpy(mm->field, buf, len);
87                 }
88             }
89             // second, marc subfield, just a char
90             else if (field == 1)
91             {
92                 mm->subfield = buf[len-2];
93             }
94             // third, pz fieldname
95             else if (field == 2) 
96             { 
97                 mm->pz = nmem_malloc(nmem, len * sizeof(char));
98                 strncpy(mm->pz, buf, len);
99             }
100
101             // new line, new record
102             if (c == '\n')
103             {
104                 field = 0;
105                 newrec = 1;
106             }
107             else
108             {
109                 field++;
110             }
111             len = 0;
112         }
113         else
114         {
115             buf[len] = c;
116             len++;
117         }
118     }
119     mm->next = NULL;
120     return mmhead;
121 }
122
123 xmlDoc *marcmap_apply(struct marcmap *marcmap, xmlDoc *xml_in)
124 {
125     char mergekey[1024];
126     char medium[32];
127     char *s;
128     NMEM nmem;
129     xmlNsPtr ns_pz;
130     xmlDocPtr xml_out;
131     xmlNodePtr xml_out_root;
132     xmlNodePtr rec_node;
133     xmlNodePtr meta_node; 
134     struct marchash *marchash;
135     struct marcfield *field;
136     struct marcsubfield *subfield;
137     struct marcmap *mmcur;
138      
139     xml_out = xmlNewDoc(BAD_CAST "1.0");
140     xml_out_root = xmlNewNode(NULL, BAD_CAST "record");
141     xmlDocSetRootElement(xml_out, xml_out_root);
142     ns_pz = xmlNewNs(xml_out_root, BAD_CAST "http://www.indexdata.com/pazpar2/1.0", BAD_CAST "pz"); 
143     nmem = nmem_create();
144     rec_node = xmlDocGetRootElement(xml_in);
145     marchash = marchash_create(nmem);
146     marchash_ingest_marcxml(marchash, rec_node);
147
148     mmcur = marcmap;
149     while (mmcur != NULL)
150     {
151         field = 0;
152         while ((field = marchash_get_field(marchash, mmcur->field, field)) != 0)
153         {
154             // field value
155             if ((mmcur->subfield == '$') && (s = field->val))
156             {
157                 meta_node = xmlNewChild(xml_out_root, ns_pz, BAD_CAST "metadata", BAD_CAST s);
158                 xmlSetProp(meta_node, BAD_CAST "type", BAD_CAST mmcur->pz); 
159             }
160             // catenate all subfields
161             else if ((mmcur->subfield == '*') && (s = marchash_catenate_subfields(field, " ", nmem)))
162             {
163                 meta_node = xmlNewChild(xml_out_root, ns_pz, BAD_CAST "metadata", BAD_CAST s);
164                 xmlSetProp(meta_node, BAD_CAST "type", BAD_CAST mmcur->pz);
165             }
166             // subfield value
167             else if (mmcur->subfield) 
168             {
169                 subfield = 0;
170                 while ((subfield = 
171                         marchash_get_subfield(mmcur->subfield,
172                                               field, subfield)) != 0)
173                 {
174                     if ((s = subfield->val) != 0)
175                     {
176                         meta_node = xmlNewChild(xml_out_root, ns_pz, BAD_CAST "metadata", BAD_CAST s);
177                         xmlSetProp(meta_node, BAD_CAST "type", BAD_CAST mmcur->pz);
178                     }
179                 }
180             }
181             
182         }
183         mmcur = mmcur->next;
184     }
185
186     // hard coded mappings
187
188     // medium
189     if ((field = marchash_get_field(marchash, "245", NULL)) && (subfield = marchash_get_subfield('h', field, NULL)))
190     {
191        strncpy(medium, subfield->val, 32);
192     }
193     else if ((field = marchash_get_field(marchash, "900", NULL)) && (subfield = marchash_get_subfield('a', field, NULL)))
194        strcpy(medium, "electronic resource");
195     else if ((field = marchash_get_field(marchash, "900", NULL)) && (subfield = marchash_get_subfield('b', field, NULL)))
196        strcpy(medium, "electronic resource");
197     else if ((field = marchash_get_field(marchash, "773", NULL)) && (subfield = marchash_get_subfield('t', field, NULL)))
198        strcpy(medium, "article");
199     else
200        strcpy(medium, "book");
201
202     meta_node = xmlNewChild(xml_out_root, ns_pz, BAD_CAST "metadata", BAD_CAST medium);
203     xmlSetProp(meta_node, BAD_CAST "type", BAD_CAST "medium");
204
205     // merge key
206     memset(mergekey, 0, 1024);
207     strcpy(mergekey, "title ");
208     if ((field = marchash_get_field(marchash, "245", NULL)) && (subfield = marchash_get_subfield('a', field, NULL)))
209         strncat(mergekey, subfield->val, 1023 - strlen(mergekey));
210     strncat(mergekey, " author ", 1023 - strlen(mergekey));
211     if ((field = marchash_get_field(marchash, "245", NULL)) && (subfield = marchash_get_subfield('a', field, NULL)))
212         strncat(mergekey, subfield->val, 1023 - strlen(mergekey));
213     strncat(mergekey, " medium ", 1023 - strlen(mergekey));
214     strncat(mergekey, medium, 1023 - strlen(mergekey));
215
216     xmlSetProp(xml_out_root, BAD_CAST "mergekey", BAD_CAST mergekey);
217
218     nmem_destroy(nmem);
219     return xml_out;
220 }
221
222 /*
223  * Local variables:
224  * c-basic-offset: 4
225  * c-file-style: "Stroustrup"
226  * indent-tabs-mode: nil
227  * End:
228  * vim: shiftwidth=4 tabstop=8 expandtab
229  */