Simple refactor due to yaz_match_xsd_element 0 check YAZ-822
[yaz-moved-to-github.git] / src / xml_to_opac.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file xml_to_opac.c
7  * \brief Implements XML to OPAC conversion
8  */
9 #if HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include <stdio.h>
14 #include <string.h>
15 #include <stdlib.h>
16
17 #include <yaz/proto.h>
18 #include <yaz/marcdisp.h>
19 #include <yaz/wrbuf.h>
20 #include <yaz/oid_db.h>
21
22 #if YAZ_HAVE_XML2
23 #include "sru-p.h"
24
25 static int match_element_next(xmlNode **ptr, const char *elem, NMEM nmem,
26                               char **val)
27 {
28     while (*ptr && (*ptr)->type != XML_ELEMENT_NODE)
29         (*ptr) = (*ptr)->next;
30     if (yaz_match_xsd_string_n_nmem(*ptr, elem, nmem, val, 0))
31     {
32         *ptr = (*ptr)->next;
33         return 1;
34     }
35     *val = 0;
36     return 0;
37 }
38
39 static int match_v_next(xmlNode **ptr, const char *elem, NMEM nmem,
40                         Odr_bool **val)
41 {
42     while (*ptr && (*ptr)->type != XML_ELEMENT_NODE)
43         (*ptr) = (*ptr)->next;
44     *val = nmem_booldup(nmem, 0);
45     if (yaz_match_xsd_element(*ptr, elem))
46     {
47         struct _xmlAttr *attr = (*ptr)->properties;
48
49         *ptr = (*ptr)->next;
50         for (; attr; attr = attr->next)
51         {
52             if (!strcmp((const char *) attr->name, "value"))
53             {
54                 if (attr->children->type == XML_TEXT_NODE)
55                 {
56                     if (attr->children->content[0] == '0')
57                         return 1;
58                     else if (attr->children->content[0] == '1')
59                     {
60                         **val = 1;
61                         return 1;
62                     }
63                 }
64             }
65         }
66     }
67     return 0;
68 }
69
70 static int bibliographicRecord(yaz_marc_t mt, xmlNode *ptr, Z_External **ext,
71                                yaz_iconv_t cd, NMEM nmem, const Odr_oid *syntax)
72 {
73     int ret = 0;
74     if (yaz_marc_read_xml(mt, ptr) == 0)
75     {
76         WRBUF wr = wrbuf_alloc();
77         if (yaz_marc_write_iso2709(mt, wr) == 0)
78         {
79             *ext = z_ext_record_oid_nmem(
80                 nmem, syntax ? syntax : yaz_oid_recsyn_usmarc,
81                 wrbuf_buf(wr), wrbuf_len(wr));
82             ret = 1;
83         }
84         wrbuf_destroy(wr);
85     }
86     return ret;
87 }
88
89 static int volume(xmlNode *ptr, Z_Volume **volp, NMEM nmem)
90 {
91     *volp = (Z_Volume *) nmem_malloc(nmem, sizeof(Z_Volume));
92
93     match_element_next(&ptr, "enumeration", nmem, &(*volp)->enumeration);
94     match_element_next(&ptr, "chronology", nmem, &(*volp)->chronology);
95     match_element_next(&ptr, "enumAndChron", nmem, &(*volp)->enumAndChron);
96     return 1;
97 }
98
99 static int volumes(xmlNode *ptr, Z_Volume ***volp, int *num, NMEM nmem)
100 {
101     int i;
102     xmlNode *ptr0 = ptr;
103
104     for (i = 0; ptr; i++)
105     {
106         while (ptr && ptr->type != XML_ELEMENT_NODE)
107             ptr = ptr->next;
108         if (!ptr)
109             break;
110         if (!yaz_match_xsd_element(ptr, "volume"))
111             return 0;
112         ptr = ptr->next;
113     }
114     *num = i;
115     *volp = (Z_Volume **) nmem_malloc(nmem, sizeof(**volp) * i);
116     ptr = ptr0;
117     for (i = 0; ptr; i++)
118     {
119         while (ptr && ptr->type != XML_ELEMENT_NODE)
120             ptr = ptr->next;
121         if (!ptr)
122             break;
123         if (!yaz_match_xsd_element(ptr, "volume"))
124             return 0;
125         volume(ptr->children, (*volp) + i, nmem);
126         ptr = ptr->next;
127     }
128     return 1;
129 }
130
131 static int circulation(xmlNode *ptr, Z_CircRecord **circp, NMEM nmem)
132 {
133     *circp = (Z_CircRecord *) nmem_malloc(nmem, sizeof(Z_CircRecord));
134
135     match_v_next(&ptr, "availableNow", nmem, &(*circp)->availableNow);
136     /* note the spelling of the ASN.1 member below */
137     match_element_next(&ptr,     "availabilityDate", nmem,
138                        &(*circp)->availablityDate);
139     match_element_next(&ptr, "availableThru", nmem, &(*circp)->availableThru);
140     match_element_next(&ptr, "restrictions", nmem, &(*circp)->restrictions);
141     match_element_next(&ptr, "itemId", nmem, &(*circp)->itemId);
142     match_v_next(&ptr, "renewable", nmem, &(*circp)->renewable);
143     match_v_next(&ptr, "onHold", nmem, &(*circp)->onHold);
144     match_element_next(&ptr, "enumAndChron", nmem, &(*circp)->enumAndChron);
145     match_element_next(&ptr, "midspine", nmem, &(*circp)->midspine);
146     match_element_next(&ptr, "temporaryLocation", nmem,
147                        &(*circp)->temporaryLocation);
148     return 1;
149 }
150
151 static int circulations(xmlNode *ptr, Z_CircRecord ***circp,
152                         int *num, NMEM nmem)
153 {
154     int i;
155     xmlNode *ptr0 = ptr;
156
157     for (i = 0; ptr; i++)
158     {
159         while (ptr && ptr->type != XML_ELEMENT_NODE)
160             ptr = ptr->next;
161         if (!ptr)
162             break;
163         if (!yaz_match_xsd_element(ptr, "circulation"))
164             return 0;
165         ptr = ptr->next;
166     }
167     *num = i;
168     *circp = (Z_CircRecord **) nmem_malloc(nmem, sizeof(**circp) * i);
169     ptr = ptr0;
170     for (i = 0; ptr; i++)
171     {
172         while (ptr && ptr->type != XML_ELEMENT_NODE)
173             ptr = ptr->next;
174         if (!ptr)
175             break;
176         if (!yaz_match_xsd_element(ptr, "circulation"))
177             return 0;
178         circulation(ptr->children, (*circp) + i, nmem);
179         ptr = ptr->next;
180     }
181     return 1;
182 }
183
184 static int holdingsRecord(xmlNode *ptr, Z_HoldingsRecord **r, NMEM nmem)
185 {
186     Z_HoldingsAndCircData *h;
187
188     *r = (Z_HoldingsRecord *)
189         nmem_malloc(nmem, sizeof(**r));
190     (*r)->which = Z_HoldingsRecord_holdingsAndCirc;
191     h = (*r)->u.holdingsAndCirc = (Z_HoldingsAndCircData *)
192         nmem_malloc(nmem, sizeof(*h));
193
194     match_element_next(&ptr, "typeOfRecord", nmem, &h->typeOfRecord);
195     match_element_next(&ptr, "encodingLevel", nmem, &h->encodingLevel);
196     match_element_next(&ptr, "format", nmem, &h->format);
197     match_element_next(&ptr, "receiptAcqStatus", nmem, &h->receiptAcqStatus);
198     match_element_next(&ptr, "generalRetention", nmem, &h->generalRetention);
199     match_element_next(&ptr, "completeness", nmem, &h->completeness);
200     match_element_next(&ptr, "dateOfReport", nmem, &h->dateOfReport);
201     match_element_next(&ptr, "nucCode", nmem, &h->nucCode);
202     match_element_next(&ptr, "localLocation", nmem, &h->localLocation);
203     match_element_next(&ptr, "shelvingLocation", nmem, &h->shelvingLocation);
204     match_element_next(&ptr, "callNumber", nmem, &h->callNumber);
205     match_element_next(&ptr, "shelvingData", nmem, &h->shelvingData);
206     match_element_next(&ptr, "copyNumber", nmem, &h->copyNumber);
207     match_element_next(&ptr, "publicNote", nmem, &h->publicNote);
208     match_element_next(&ptr, "reproductionNote", nmem, &h->reproductionNote);
209     match_element_next(&ptr, "termsUseRepro", nmem, &h->termsUseRepro);
210     match_element_next(&ptr, "enumAndChron", nmem, &h->enumAndChron);
211
212     h->num_volumes = 0;
213     h->volumes = 0;
214     while (ptr && ptr->type != XML_ELEMENT_NODE)
215         ptr = ptr->next;
216     if (yaz_match_xsd_element(ptr, "volumes"))
217     {
218         volumes(ptr->children, &h->volumes, &h->num_volumes, nmem);
219         ptr = ptr->next;
220     }
221
222     h->num_circulationData = 0;
223     h->circulationData = 0;
224     while (ptr && ptr->type != XML_ELEMENT_NODE)
225         ptr = ptr->next;
226     if (yaz_match_xsd_element(ptr, "circulations"))
227     {
228         circulations(ptr->children, &h->circulationData,
229                      &h->num_circulationData, nmem);
230         ptr = ptr->next;
231     }
232     return 1;
233 }
234
235 static int yaz_xml_to_opac_ptr(yaz_marc_t mt, xmlNode *ptr,
236                                Z_OPACRecord **dst,
237                                yaz_iconv_t cd, NMEM nmem,
238                                const Odr_oid *syntax)
239 {
240     int i;
241     Z_External *ext = 0;
242     Z_OPACRecord *opac;
243     xmlNode *ptr0;
244
245     if (!nmem)
246         nmem = yaz_marc_get_nmem(mt);
247     if (!yaz_match_xsd_element(ptr, "opacRecord"))
248         return 0;
249     ptr = ptr->children;
250     while (ptr && ptr->type != XML_ELEMENT_NODE)
251         ptr = ptr->next;
252     if (!yaz_match_xsd_element(ptr, "bibliographicRecord"))
253         return 0;
254     if (!bibliographicRecord(mt, ptr->children, &ext, cd, nmem, syntax))
255         return 0;
256     *dst = opac = (Z_OPACRecord *) nmem_malloc(nmem, sizeof(*opac));
257     opac->num_holdingsData = 0;
258     opac->holdingsData = 0;
259     opac->bibliographicRecord = ext;
260
261     ptr = ptr->next;
262     while (ptr && ptr->type != XML_ELEMENT_NODE)
263         ptr = ptr->next;
264     if (!yaz_match_xsd_element(ptr, "holdings"))
265         return 0;
266
267     ptr = ptr->children;
268     ptr0 = ptr;
269
270     for (i = 0; ptr; i++)
271     {
272         while (ptr && ptr->type != XML_ELEMENT_NODE)
273             ptr = ptr->next;
274         if (!ptr)
275             break;
276         if (!yaz_match_xsd_element(ptr, "holding"))
277             return 0;
278         ptr = ptr->next;
279     }
280     opac->num_holdingsData = i;
281     opac->holdingsData = (Z_HoldingsRecord **)
282         nmem_malloc(nmem, sizeof(*opac->holdingsData) * i);
283     ptr = ptr0;
284     for (i = 0; ptr; i++)
285     {
286         while (ptr && ptr->type != XML_ELEMENT_NODE)
287             ptr = ptr->next;
288         if (!ptr)
289             break;
290         if (!yaz_match_xsd_element(ptr, "holding"))
291             return 0;
292         if (!holdingsRecord(ptr->children, opac->holdingsData + i, nmem))
293             return 0;
294         ptr = ptr->next;
295     }
296     return 1;
297 }
298
299 int yaz_xml_to_opac(yaz_marc_t mt, const char *buf_in, size_t size_in,
300                     Z_OPACRecord **dst, yaz_iconv_t cd, NMEM nmem,
301                     const Odr_oid *syntax)
302 {
303     xmlDocPtr doc = xmlParseMemory(buf_in, size_in);
304     int r = 0;
305     if (doc)
306     {
307         r = yaz_xml_to_opac_ptr(mt, xmlDocGetRootElement(doc), dst, cd, nmem,
308                                 syntax);
309         xmlFreeDoc(doc);
310     }
311     return r;
312 }
313
314
315 #endif
316
317 /*
318  * Local variables:
319  * c-basic-offset: 4
320  * c-file-style: "Stroustrup"
321  * indent-tabs-mode: nil
322  * End:
323  * vim: shiftwidth=4 tabstop=8 expandtab
324  */
325