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