YAZ 5.35.1
record_render.c
Go to the documentation of this file.
1/* This file is part of the YAZ toolkit.
2 * Copyright (C) Index Data
3 * See the file LICENSE for details.
4 */
9#if HAVE_CONFIG_H
10#include <config.h>
11#endif
12
13#include <assert.h>
14#include <string.h>
15#include <errno.h>
16
17#include <yaz/marcdisp.h>
18#include <yaz/record_render.h>
19#include <yaz/yaz-iconv.h>
20#include <yaz/proto.h>
21#include <yaz/oid_db.h>
22#include <yaz/nmem_xml.h>
23#include <yaz/base64.h>
24
25#if YAZ_HAVE_XML2
26#include <libxml/parser.h>
27#include <libxml/xpath.h>
28#include <libxml/xpathInternals.h>
29#endif
30
31static yaz_iconv_t iconv_create_charset(const char *record_charset,
32 yaz_iconv_t *cd2,
33 const char *marc_buf,
34 int sz)
35{
36 char charset_buf[40];
37 yaz_iconv_t cd = 0;
38 char *from_set1 = 0;
39 char *from_set2 = 0;
40 char *to_set = "utf-8";
41 if (record_charset && *record_charset)
42 {
43 char *cp = charset_buf;
44
45 strncpy(charset_buf, record_charset, sizeof(charset_buf)-1);
46 charset_buf[sizeof(charset_buf)-1] = '\0';
47
48 from_set1 = cp;
49 while (*cp && *cp != ',' && *cp != '/')
50 cp++;
51 if (*cp == '/')
52 {
53 *cp++ = '\0'; /* terminate from_set1 */
54 from_set2 = cp;
55 while (*cp && *cp != ',')
56 cp++;
57 }
58 if (*cp == ',')
59 {
60 *cp++ = '\0'; /* terminate from_set1 or from_set2 */
61 to_set = cp;
62 while (*cp)
63 cp++;
64 }
65 }
66
67 if (from_set1)
68 {
69 if (yaz_marc_check_marc21_coding(from_set1, marc_buf, sz))
70 from_set1 = "utf-8";
71 cd = yaz_iconv_open(to_set, from_set1);
72 }
73 if (cd2)
74 {
75 if (from_set2)
76 *cd2 = yaz_iconv_open(to_set, from_set2);
77 else
78 *cd2 = 0;
79 }
80 return cd;
81}
82
83static const char *return_marc_record(WRBUF wrbuf,
84 int marc_type,
85 int *len,
86 const char *buf, int sz,
87 const char *record_charset)
88{
89 yaz_iconv_t cd = iconv_create_charset(record_charset, 0, buf, sz);
91 const char *ret_string = 0;
92
93 if (cd)
94 yaz_marc_iconv(mt, cd);
95 yaz_marc_xml(mt, marc_type);
96 if (yaz_marc_decode_wrbuf(mt, buf, sz, wrbuf) > 0)
97 {
98 *len = wrbuf_len(wrbuf);
99 ret_string = wrbuf_cstr(wrbuf);
100 }
102 if (cd)
103 yaz_iconv_close(cd);
104 return ret_string;
105}
106
107static const char *return_opac_record(WRBUF wrbuf,
108 int marc_type,
109 int *len,
110 Z_OPACRecord *opac_rec,
111 const char *record_charset)
112{
113 yaz_iconv_t cd, cd2;
114 const char *marc_buf = 0;
115 int marc_sz = 0;
117
118 if (opac_rec->bibliographicRecord)
119 {
120 Z_External *ext = opac_rec->bibliographicRecord;
121 if (ext->which == Z_External_octet)
122 {
123 marc_buf = (const char *) ext->u.octet_aligned->buf;
124 marc_sz = ext->u.octet_aligned->len;
125 }
126 }
127 cd = iconv_create_charset(record_charset, &cd2, marc_buf, marc_sz);
128
129 if (cd)
130 yaz_marc_iconv(mt, cd);
131 yaz_marc_xml(mt, marc_type);
132
133 if (cd2)
134 yaz_opac_decode_wrbuf2(mt, opac_rec, wrbuf, cd2);
135 else
136 yaz_opac_decode_wrbuf(mt, opac_rec, wrbuf);
137
139
140 if (cd)
141 yaz_iconv_close(cd);
142 if (cd2)
143 yaz_iconv_close(cd2);
144 *len = wrbuf_len(wrbuf);
145 return wrbuf_cstr(wrbuf);
146}
147
149 int *len,
150 const char *buf, int sz,
151 const char *record_charset)
152{
153 yaz_iconv_t cd = iconv_create_charset(record_charset, 0, 0, 0);
154
155 if (cd)
156 {
157 wrbuf_iconv_write(wrbuf, cd, buf, sz);
159
160 buf = wrbuf_cstr(wrbuf);
161 sz = wrbuf_len(wrbuf);
162 yaz_iconv_close(cd);
163 }
164 *len = sz;
165 return buf;
166}
167
168static const char *return_record_wrbuf(WRBUF wrbuf, int *len,
169 Z_NamePlusRecord *npr,
170 int marctype, const char *charset)
171{
173 const Odr_oid *oid = r->direct_reference;
174
176 /* render bibliographic record .. */
177 if (r->which == Z_External_OPAC)
178 {
179 return return_opac_record(wrbuf, marctype, len,
180 r->u.opac, charset);
181 }
182 if (r->which == Z_External_sutrs)
183 return return_string_record(wrbuf, len,
184 (char*) r->u.sutrs->buf,
185 r->u.sutrs->len,
186 charset);
187 else if (r->which == Z_External_octet)
188 {
193 {
194 const char *ret_buf = return_marc_record(
195 wrbuf, marctype, len,
196 (const char *) r->u.octet_aligned->buf,
197 r->u.octet_aligned->len,
198 charset);
199 if (ret_buf)
200 return ret_buf;
201 /* not ISO2709. Return fail unless raw (ISO2709) is wanted */
202 if (yaz_oid_is_iso2709(oid) && marctype != YAZ_MARC_ISO2709)
203 return 0;
204 }
205 return return_string_record(wrbuf, len,
206 (const char *) r->u.octet_aligned->buf,
207 r->u.octet_aligned->len,
208 charset);
209 }
210 else if (r->which == Z_External_grs1)
211 {
213 return return_string_record(wrbuf, len,
216 charset);
217 }
218 return 0;
219}
220
221static const char *get_record_format(WRBUF wrbuf, int *len,
222 Z_NamePlusRecord *npr,
223 int marctype, const char *charset,
224 const char *format)
225{
226 const char *res = return_record_wrbuf(wrbuf, len, npr, marctype, charset);
227#if YAZ_HAVE_XML2
228 if (*format == '1')
229 {
230 /* try to XML format res */
231 xmlDocPtr doc;
232 xmlKeepBlanksDefault(0); /* get get xmlDocFormatMemory to work! */
233 doc = xmlParseMemory(res, *len);
234 if (doc)
235 {
236 xmlChar *xml_mem;
237 int xml_size;
238 xmlDocDumpFormatMemory(doc, &xml_mem, &xml_size, 1);
240 wrbuf_write(wrbuf, (const char *) xml_mem, xml_size);
241 xmlFree(xml_mem);
242 xmlFreeDoc(doc);
243 res = wrbuf_cstr(wrbuf);
244 *len = wrbuf_len(wrbuf);
245 }
246 }
247#endif
248 return res;
249}
250
251#if YAZ_HAVE_XML2
252static int replace_node(NMEM nmem, xmlNode *ptr,
253 const char *type_spec, char *record_buf)
254{
255 int ret = -1;
256 const char *res;
257 int len;
258 int m_len;
261 Z_NamePlusRecord *npr = odr_malloc(odr, sizeof(*npr));
263
264 if (atoi_n_check(record_buf, 5, &m_len))
265 npr->u.databaseRecord =
266 z_ext_record_usmarc(odr, record_buf, strlen(record_buf));
267 else
268 npr->u.databaseRecord =
269 z_ext_record_xml(odr, record_buf, strlen(record_buf));
270 res = yaz_record_render(npr, 0, wrbuf, type_spec, &len);
271 if (res)
272 {
273 xmlDoc *doc = xmlParseMemory(res, strlen(res));
274 if (doc)
275 {
276 xmlNode *nptr = xmlCopyNode(xmlDocGetRootElement(doc), 1);
277 xmlReplaceNode(ptr, nptr);
278 xmlFreeDoc(doc);
279 }
280 else
281 {
282 xmlNode *nptr = xmlNewText(BAD_CAST res);
283 xmlReplaceNode(ptr, nptr);
284 }
285 ret = 0;
286 }
289 return ret;
290}
291#endif
292
293static const char *base64_render(NMEM nmem, WRBUF wrbuf,
294 const char *buf, int *len,
295 const char *expr, const char *type_spec)
296{
297#if YAZ_HAVE_XML2
298 xmlDocPtr doc = xmlParseMemory(buf, *len);
299 if (doc)
300 {
301 xmlChar *buf_out;
302 int len_out;
303 xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
304 if (xpathCtx)
305 {
306 xmlXPathObjectPtr xpathObj =
307 xmlXPathEvalExpression((const xmlChar *) expr, xpathCtx);
308 if (xpathObj)
309 {
310 xmlNodeSetPtr nodes = xpathObj->nodesetval;
311 if (nodes)
312 {
313 int i;
314 for (i = 0; i < nodes->nodeNr; i++)
315 {
316 xmlNode *ptr = nodes->nodeTab[i];
317 if (ptr->type == XML_TEXT_NODE)
318 {
319 const char *input =
320 nmem_text_node_cdata(ptr, nmem);
321 char *output = nmem_malloc(
322 nmem, strlen(input) + 1);
323 if (yaz_base64decode(input, output) == 0)
324 {
325 if (!replace_node(nmem, ptr, type_spec, output))
326 {
327 /* replacement OK */
328 xmlFreeNode(ptr);
329 /* unset below to avoid a bad reference in
330 xmlXPathFreeObject below */
331 nodes->nodeTab[i] = 0;
332 }
333 }
334 }
335 }
336 }
337 xmlXPathFreeObject(xpathObj);
338 }
339 xmlXPathFreeContext(xpathCtx);
340 }
341 xmlDocDumpMemory(doc, &buf_out, &len_out);
342 if (buf_out)
343 {
345 wrbuf_write(wrbuf, (const char *) buf_out, len_out);
346 buf = wrbuf_cstr(wrbuf);
347 *len = len_out;
348 }
349 xmlFreeDoc(doc);
350 xmlFree(buf_out);
351 }
352#endif
353 return buf;
354}
355
356const char *yaz_record_render(Z_NamePlusRecord *npr, const char *schema,
357 WRBUF wrbuf,
358 const char *type_spec, int *len)
359{
360 const char *ret = 0;
361 NMEM nmem = 0;
362 char *base64_xpath = 0;
363 size_t i;
364 char type[40];
365 char charset[40];
366 char format[3];
367 const char *cp = type_spec;
368 int len0;
369
370 if (!len)
371 len = &len0;
372
373 for (i = 0; cp[i] && cp[i] != ';' && cp[i] != ' ' && i < sizeof(type)-1;
374 i++)
375 type[i] = cp[i];
376 type[i] = '\0';
377 charset[0] = '\0';
378 format[0] = '\0';
379 while (1)
380 {
381 while (cp[i] == ' ')
382 i++;
383 if (cp[i] != ';')
384 break;
385 i++;
386 while (cp[i] == ' ')
387 i++;
388 if (!strncmp(cp + i, "charset=", 8))
389 {
390 size_t j = 0;
391 i = i + 8; /* skip charset= */
392 while (cp[i] == ' ')
393 i++;
394 for (j = 0; cp[i] && cp[i] != ';' && cp[i] != ' '; i++)
395 {
396 if (j < sizeof(charset)-1)
397 charset[j++] = cp[i];
398 }
399 charset[j] = '\0';
400 }
401 else if (!strncmp(cp + i, "format=", 7))
402 {
403 size_t j = 0;
404 i = i + 7;
405 while (cp[i] == ' ')
406 i++;
407 for (j = 0; cp[i] && cp[i] != ';' && cp[i] != ' '; i++)
408 {
409 if (j < sizeof(format)-1)
410 format[j++] = cp[i];
411 }
412 format[j] = '\0';
413 }
414 else if (!strncmp(cp + i, "base64=", 7))
415 {
416 size_t i0;
417 i = i + 7;
418 while (cp[i] == ' ')
419 i++;
420 i0 = i;
421 while (cp[i] && cp[i] != ';')
422 i++;
423
424 nmem = nmem_create();
425 base64_xpath = nmem_strdupn(nmem, cp + i0, i - i0);
426 }
427 }
428 if (!strcmp(type, "database"))
429 {
430 *len = (npr->databaseName ? strlen(npr->databaseName) : 0);
431 ret = npr->databaseName;
432 }
433 else if (!strcmp(type, "schema"))
434 {
435 *len = schema ? strlen(schema) : 0;
436 ret = schema;
437 }
438 else if (!strcmp(type, "syntax"))
439 {
440 const char *desc = 0;
442 {
445 }
446 if (!desc)
447 desc = "none";
448 *len = strlen(desc);
449 ret = desc;
450 }
452 ;
453 else if (!strcmp(type, "render"))
454 {
455 ret = get_record_format(wrbuf, len, npr, YAZ_MARC_LINE, charset, format);
456 }
457 else if (!strcmp(type, "xml"))
458 {
459 ret = get_record_format(wrbuf, len, npr, YAZ_MARC_MARCXML, charset,
460 format);
461 }
462 else if (!strcmp(type, "txml"))
463 {
464 ret = get_record_format(wrbuf, len, npr, YAZ_MARC_TURBOMARC, charset,
465 format);
466 }
467 else if (!strcmp(type, "json"))
468 {
469 ret = get_record_format(wrbuf, len, npr, YAZ_MARC_JSON, charset,
470 format);
471 }
472 else if (!strcmp(type, "raw"))
473 {
474 ret = get_record_format(wrbuf, len, npr, YAZ_MARC_ISO2709, charset,
475 format);
476 }
477 else if (!strcmp(type, "ext"))
478 {
479 *len = -1;
480 ret = (const char *) npr->u.databaseRecord;
481 }
482 else if (!strcmp(type, "opac"))
483 {
485 ret = get_record_format(wrbuf, len, npr, YAZ_MARC_MARCXML, charset,
486 format);
487 }
488
489 if (base64_xpath && *len != -1)
490 {
491 char *type_spec = nmem_malloc(nmem,
492 strlen(type) + strlen(charset) + 11);
493 strcpy(type_spec, type);
494 if (*charset)
495 {
496 strcat(type_spec, "; charset=");
497 strcat(type_spec, charset);
498 }
499 ret = base64_render(nmem, wrbuf, ret, len, base64_xpath, type_spec);
500 }
501 nmem_destroy(nmem);
502 return ret;
503}
504
505/*
506 * Local variables:
507 * c-basic-offset: 4
508 * c-file-style: "Stroustrup"
509 * indent-tabs-mode: nil
510 * End:
511 * vim: shiftwidth=4 tabstop=8 expandtab
512 */
513
int atoi_n_check(const char *buf, int size, int *val)
like atoi_n but checks for proper formatting
Definition atoin.c:32
int yaz_base64decode(const char *in, char *out)
decodes Base64 string
Definition base64.c:82
Header for Base64 utilities.
Header for errno utilities.
void yaz_display_grs1(WRBUF wrbuf, Z_GenericRecord *r, int flags)
Performs "pretty" display of GRS-1 record to WRBUF.
Definition grs1disp.c:125
enum l_file_type type
Definition log.c:47
int yaz_marc_check_marc21_coding(const char *charset, const char *marc_buf, int sz)
check if MARC21 is UTF-8 encoded
Definition marcdisp.c:1490
yaz_marc_t yaz_marc_create(void)
construct yaz_marc_t handle
Definition marcdisp.c:102
void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
set iconv handle for character set conversion
Definition marcdisp.c:1387
void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
set XML mode YAZ_MARC_LINE, YAZ_MARCXML, YAZ_MARC_ISO2709 ..
Definition marcdisp.c:1376
void yaz_marc_destroy(yaz_marc_t mt)
destroy yaz_marc_t handle
Definition marcdisp.c:120
int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
decodes ISO2709/MARC buffer and stores result in WRBUF
Definition marcdisp.c:1351
MARC conversion.
#define YAZ_MARC_MARCXML
Output format: MARCXML.
Definition marcdisp.h:70
#define YAZ_MARC_ISO2709
Output format: ISO2709.
Definition marcdisp.h:72
#define YAZ_MARC_LINE
Output format: Line-format.
Definition marcdisp.h:64
#define YAZ_MARC_JSON
Output format: JSON.
Definition marcdisp.h:80
#define YAZ_MARC_TURBOMARC
Output format: Turbo MARC Index Data format (XML based)
Definition marcdisp.h:78
NMEM nmem_create(void)
returns new NMEM handle
Definition nmem.c:181
void * nmem_malloc(NMEM n, size_t size)
allocates memory block on NMEM handle
Definition nmem.c:145
void nmem_destroy(NMEM n)
destroys NMEM handle and memory associated with it
Definition nmem.c:204
Header for Nibble Memory functions + Libxml2 specific stuff.
char * nmem_strdupn(NMEM mem, const char *src, size_t n)
allocates string of certain size on NMEM handle
Definition nmemsdup.c:33
char * nmem_text_node_cdata(const xmlNode *ptr_cdata, NMEM nmem)
copies TEXT Libxml2 node data to NMEM
Definition nmemsdup.c:145
ODR odr_createmem(int direction)
Definition odr.c:200
void odr_destroy(ODR o)
Definition odr.c:253
#define ODR_ENCODE
Definition odr.h:96
void * odr_malloc(ODR o, size_t size)
Definition odr_mem.c:31
int yaz_oid_is_iso2709(const Odr_oid *oid)
checks if OID refers to MARC transfer syntax
Definition oid_db.c:119
const char * yaz_oid_to_string(yaz_oid_db_t oid_db, const Odr_oid *oid, oid_class *oclass)
maps raw OID to string
Definition oid_db.c:78
yaz_oid_db_t yaz_oid_std(void)
returns standard OID database
Definition oid_db.c:33
Header for OID database.
const Odr_oid yaz_oid_recsyn_html[]
Definition oid_std.c:77
const Odr_oid yaz_oid_recsyn_mab[]
Definition oid_std.c:50
const Odr_oid yaz_oid_recsyn_xml[]
Definition oid_std.c:89
const Odr_oid yaz_oid_recsyn_application_xml[]
Definition oid_std.c:91
int oid_oidcmp(const Odr_oid *o1, const Odr_oid *o2)
compares OIDs
Definition oid_util.c:34
short Odr_oid
Definition oid_util.h:42
void yaz_opac_decode_wrbuf(yaz_marc_t mt, Z_OPACRecord *r, WRBUF wrbuf)
Performs "pretty" display of OPAC record to WRBUF using marc_t.
void yaz_opac_decode_wrbuf2(yaz_marc_t mt, Z_OPACRecord *r, WRBUF wrbuf, yaz_iconv_t cd2)
Performs "pretty" display of OPAC record to WRBUF using marc_t.
Definition opac_to_xml.c:62
Header for Z39.50 Protocol.
Z_External * z_ext_record_xml(ODR o, const char *buf, int len)
encodes EXTERNAL XML record
Definition prt-ext.c:368
Z_External * z_ext_record_usmarc(ODR o, const char *buf, int len)
encodes EXTERNAL USMARC/MARC21 record
Definition prt-ext.c:378
#define Z_External_octet
Definition prt-ext.h:66
#define Z_External_grs1
Definition prt-ext.h:74
#define Z_External_sutrs
Definition prt-ext.h:69
#define Z_External_OPAC
Definition prt-ext.h:80
static const char * return_opac_record(WRBUF wrbuf, int marc_type, int *len, Z_OPACRecord *opac_rec, const char *record_charset)
static yaz_iconv_t iconv_create_charset(const char *record_charset, yaz_iconv_t *cd2, const char *marc_buf, int sz)
static const char * return_record_wrbuf(WRBUF wrbuf, int *len, Z_NamePlusRecord *npr, int marctype, const char *charset)
static const char * base64_render(NMEM nmem, WRBUF wrbuf, const char *buf, int *len, const char *expr, const char *type_spec)
static const char * return_marc_record(WRBUF wrbuf, int marc_type, int *len, const char *buf, int sz, const char *record_charset)
static const char * return_string_record(WRBUF wrbuf, int *len, const char *buf, int sz, const char *record_charset)
const char * yaz_record_render(Z_NamePlusRecord *npr, const char *schema, WRBUF wrbuf, const char *type_spec, int *len)
render records (ZOOM style)
static int replace_node(NMEM nmem, xmlNode *ptr, const char *type_spec, char *record_buf)
static const char * get_record_format(WRBUF wrbuf, int *len, Z_NamePlusRecord *npr, int marctype, const char *charset, const char *format)
Record render header.
int yaz_iconv_close(yaz_iconv_t cd)
just like iconv_close(3)
Definition siconv.c:284
yaz_iconv_t yaz_iconv_open(const char *tocode, const char *fromcode)
just like iconv_open(3)
Definition siconv.c:95
structure for all known EXTERNALs
Definition prt-ext.h:59
Z_OPACRecord * opac
Definition prt-ext.h:122
int which
Definition prt-ext.h:63
Z_GenericRecord * grs1
Definition prt-ext.h:115
union Z_External::@27 u
Z_SUTRS * sutrs
Definition prt-ext.h:109
Odr_oid * direct_reference
Definition prt-ext.h:60
Odr_oct * octet_aligned
Definition prt-ext.h:105
Z_External * databaseRecord
Definition z-core.h:708
Z_DatabaseName * databaseName
Definition z-core.h:705
union Z_NamePlusRecord::@54 u
Z_External * bibliographicRecord
Definition z-opac.h:37
int len
Definition odr.h:102
char * buf
Definition odr.h:101
Definition odr.h:125
string buffer
Definition wrbuf.h:43
the internals of a yaz_marc_t handle
Definition marcdisp.c:86
void wrbuf_destroy(WRBUF b)
destroy WRBUF and its buffer
Definition wrbuf.c:38
void wrbuf_iconv_reset(WRBUF b, yaz_iconv_t cd)
iconv reset(flush) to WRBUF
Definition wrbuf.c:286
const char * wrbuf_cstr(WRBUF b)
returns WRBUF content as C-string
Definition wrbuf.c:299
void wrbuf_rewind(WRBUF b)
empty WRBUF content (length of buffer set to 0)
Definition wrbuf.c:47
WRBUF wrbuf_alloc(void)
construct WRBUF
Definition wrbuf.c:25
void wrbuf_iconv_write(WRBUF b, yaz_iconv_t cd, const char *buf, size_t size)
Converts buffer using iconv and appends to WRBUF.
Definition wrbuf.c:248
void wrbuf_write(WRBUF b, const char *buf, size_t size)
append constant size buffer to WRBUF
Definition wrbuf.c:68
#define wrbuf_buf(b)
Definition wrbuf.h:270
#define wrbuf_len(b)
Definition wrbuf.h:269
Header for YAZ iconv interface.
#define Z_NamePlusRecord_databaseRecord
Definition z-core.h:713