1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2010 Index Data
3 * See the file LICENSE for details.
8 * \brief Implements MARC conversion utilities
24 #include <yaz/marcdisp.h>
25 #include <yaz/wrbuf.h>
26 #include <yaz/yaz-util.h>
27 #include <yaz/nmem_xml.h>
28 #include <yaz/snprintf.h>
31 #include <libxml/parser.h>
32 #include <libxml/tree.h>
35 enum yaz_collection_state {
41 /** \brief node types for yaz_marc_node */
42 enum YAZ_MARC_NODE_TYPE
45 YAZ_MARC_CONTROLFIELD,
50 /** \brief represets a data field */
51 struct yaz_marc_datafield {
54 struct yaz_marc_subfield *subfields;
57 /** \brief represents a control field */
58 struct yaz_marc_controlfield {
63 /** \brief a comment node */
64 struct yaz_marc_comment {
68 /** \brief MARC node */
69 struct yaz_marc_node {
70 enum YAZ_MARC_NODE_TYPE which;
72 struct yaz_marc_datafield datafield;
73 struct yaz_marc_controlfield controlfield;
77 struct yaz_marc_node *next;
80 /** \brief represents a subfield */
81 struct yaz_marc_subfield {
83 struct yaz_marc_subfield *next;
86 /** \brief the internals of a yaz_marc_t handle */
93 int write_using_libxml2;
95 enum yaz_collection_state enable_collection;
100 struct yaz_marc_node *nodes;
101 struct yaz_marc_node **nodes_pp;
102 struct yaz_marc_subfield **subfield_pp;
105 yaz_marc_t yaz_marc_create(void)
107 yaz_marc_t mt = (yaz_marc_t) xmalloc(sizeof(*mt));
108 mt->output_format = YAZ_MARC_LINE;
110 mt->write_using_libxml2 = 0;
111 mt->enable_collection = no_collection;
112 mt->m_wr = wrbuf_alloc();
115 strcpy(mt->subfield_str, " $");
116 strcpy(mt->endline_str, "\n");
118 mt->nmem = nmem_create();
123 void yaz_marc_destroy(yaz_marc_t mt)
127 nmem_destroy(mt->nmem);
128 wrbuf_destroy(mt->m_wr);
129 xfree(mt->leader_spec);
133 NMEM yaz_marc_get_nmem(yaz_marc_t mt)
138 static void marc_iconv_reset(yaz_marc_t mt, WRBUF wr)
140 wrbuf_iconv_reset(wr, mt->iconv_cd);
143 static int marc_exec_leader(const char *leader_spec, char *leader,
147 static struct yaz_marc_node *yaz_marc_add_node(yaz_marc_t mt)
149 struct yaz_marc_node *n = (struct yaz_marc_node *)
150 nmem_malloc(mt->nmem, sizeof(*n));
153 mt->nodes_pp = &n->next;
158 void yaz_marc_add_controlfield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
159 const xmlNode *ptr_data)
161 struct yaz_marc_node *n = yaz_marc_add_node(mt);
162 n->which = YAZ_MARC_CONTROLFIELD;
163 n->u.controlfield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
164 n->u.controlfield.data = nmem_text_node_cdata(ptr_data, mt->nmem);
167 void yaz_marc_add_controlfield_turbo_xml(yaz_marc_t mt, const char *tag,
168 const xmlNode *ptr_data)
170 struct yaz_marc_node *n = yaz_marc_add_node(mt);
171 n->which = YAZ_MARC_CONTROLFIELD;
172 n->u.controlfield.tag = tag;
173 n->u.controlfield.data = nmem_text_node_cdata(ptr_data, mt->nmem);
179 void yaz_marc_add_comment(yaz_marc_t mt, char *comment)
181 struct yaz_marc_node *n = yaz_marc_add_node(mt);
182 n->which = YAZ_MARC_COMMENT;
183 n->u.comment = nmem_strdup(mt->nmem, comment);
186 void yaz_marc_cprintf(yaz_marc_t mt, const char *fmt, ...)
192 yaz_vsnprintf(buf, sizeof(buf)-1, fmt, ap);
193 yaz_marc_add_comment(mt, buf);
197 int yaz_marc_get_debug(yaz_marc_t mt)
202 void yaz_marc_add_leader(yaz_marc_t mt, const char *leader, size_t leader_len)
204 struct yaz_marc_node *n = yaz_marc_add_node(mt);
205 n->which = YAZ_MARC_LEADER;
206 n->u.leader = nmem_strdupn(mt->nmem, leader, leader_len);
207 marc_exec_leader(mt->leader_spec, n->u.leader, leader_len);
210 void yaz_marc_add_controlfield(yaz_marc_t mt, const char *tag,
211 const char *data, size_t data_len)
213 struct yaz_marc_node *n = yaz_marc_add_node(mt);
214 n->which = YAZ_MARC_CONTROLFIELD;
215 n->u.controlfield.tag = nmem_strdup(mt->nmem, tag);
216 n->u.controlfield.data = nmem_strdupn(mt->nmem, data, data_len);
222 sprintf(msg, "controlfield:");
223 for (i = 0; i < 16 && i < data_len; i++)
224 sprintf(msg + strlen(msg), " %02X", data[i] & 0xff);
226 sprintf(msg + strlen(msg), " ..");
227 yaz_marc_add_comment(mt, msg);
231 void yaz_marc_add_datafield(yaz_marc_t mt, const char *tag,
232 const char *indicator, size_t indicator_len)
234 struct yaz_marc_node *n = yaz_marc_add_node(mt);
235 n->which = YAZ_MARC_DATAFIELD;
236 n->u.datafield.tag = nmem_strdup(mt->nmem, tag);
237 n->u.datafield.indicator =
238 nmem_strdupn(mt->nmem, indicator, indicator_len);
239 n->u.datafield.subfields = 0;
241 /* make subfield_pp the current (last one) */
242 mt->subfield_pp = &n->u.datafield.subfields;
246 void yaz_marc_add_datafield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
247 const char *indicator, size_t indicator_len)
249 struct yaz_marc_node *n = yaz_marc_add_node(mt);
250 n->which = YAZ_MARC_DATAFIELD;
251 n->u.datafield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
252 n->u.datafield.indicator =
253 nmem_strdupn(mt->nmem, indicator, indicator_len);
254 n->u.datafield.subfields = 0;
256 /* make subfield_pp the current (last one) */
257 mt->subfield_pp = &n->u.datafield.subfields;
260 struct yaz_marc_node* yaz_marc_add_datafield_turbo_xml(yaz_marc_t mt, char *tag_value)
262 struct yaz_marc_node *n = yaz_marc_add_node(mt);
263 n->which = YAZ_MARC_DATAFIELD;
264 n->u.datafield.tag = tag_value;
265 n->u.datafield.indicator = 0;
266 n->u.datafield.subfields = 0;
268 /* make subfield_pp the current (last one) */
269 mt->subfield_pp = &n->u.datafield.subfields;
273 void yaz_marc_datafield_set_indicators(struct yaz_marc_node *n, char *indicator)
275 n->u.datafield.indicator = indicator;
280 void yaz_marc_add_subfield(yaz_marc_t mt,
281 const char *code_data, size_t code_data_len)
288 sprintf(msg, "subfield:");
289 for (i = 0; i < 16 && i < code_data_len; i++)
290 sprintf(msg + strlen(msg), " %02X", code_data[i] & 0xff);
291 if (i < code_data_len)
292 sprintf(msg + strlen(msg), " ..");
293 yaz_marc_add_comment(mt, msg);
298 struct yaz_marc_subfield *n = (struct yaz_marc_subfield *)
299 nmem_malloc(mt->nmem, sizeof(*n));
300 n->code_data = nmem_strdupn(mt->nmem, code_data, code_data_len);
302 /* mark subfield_pp to point to this one, so we append here next */
303 *mt->subfield_pp = n;
304 mt->subfield_pp = &n->next;
308 void yaz_marc_set_leader(yaz_marc_t mt, const char *leader_c,
309 int *indicator_length,
310 int *identifier_length,
312 int *length_data_entry,
313 int *length_starting,
314 int *length_implementation)
318 memcpy(leader, leader_c, 24);
320 if (!atoi_n_check(leader+10, 1, indicator_length))
323 "Indicator length at offset 10 should hold a digit."
326 *indicator_length = 2;
328 if (!atoi_n_check(leader+11, 1, identifier_length))
331 "Identifier length at offset 11 should hold a digit."
334 *identifier_length = 2;
336 if (!atoi_n_check(leader+12, 5, base_address))
339 "Base address at offsets 12..16 should hold a number."
343 if (!atoi_n_check(leader+20, 1, length_data_entry))
346 "Length data entry at offset 20 should hold a digit."
348 *length_data_entry = 4;
351 if (!atoi_n_check(leader+21, 1, length_starting))
354 "Length starting at offset 21 should hold a digit."
356 *length_starting = 5;
359 if (!atoi_n_check(leader+22, 1, length_implementation))
362 "Length implementation at offset 22 should hold a digit."
364 *length_implementation = 0;
370 yaz_marc_cprintf(mt, "Indicator length %5d", *indicator_length);
371 yaz_marc_cprintf(mt, "Identifier length %5d", *identifier_length);
372 yaz_marc_cprintf(mt, "Base address %5d", *base_address);
373 yaz_marc_cprintf(mt, "Length data entry %5d", *length_data_entry);
374 yaz_marc_cprintf(mt, "Length starting %5d", *length_starting);
375 yaz_marc_cprintf(mt, "Length implementation %5d", *length_implementation);
377 yaz_marc_add_leader(mt, leader, 24);
380 void yaz_marc_subfield_str(yaz_marc_t mt, const char *s)
382 strncpy(mt->subfield_str, s, sizeof(mt->subfield_str)-1);
383 mt->subfield_str[sizeof(mt->subfield_str)-1] = '\0';
386 void yaz_marc_endline_str(yaz_marc_t mt, const char *s)
388 strncpy(mt->endline_str, s, sizeof(mt->endline_str)-1);
389 mt->endline_str[sizeof(mt->endline_str)-1] = '\0';
392 /* try to guess how many bytes the identifier really is! */
393 static size_t cdata_one_character(yaz_marc_t mt, const char *buf)
398 for (i = 1; i<5; i++)
401 size_t outbytesleft = sizeof(outbuf);
403 const char *inp = buf;
405 size_t inbytesleft = i;
406 size_t r = yaz_iconv(mt->iconv_cd, (char**) &inp, &inbytesleft,
407 &outp, &outbytesleft);
408 if (r != (size_t) (-1))
409 return i; /* got a complete sequence */
411 return 1; /* giving up */
413 return 1; /* we don't know */
416 void yaz_marc_reset(yaz_marc_t mt)
418 nmem_reset(mt->nmem);
420 mt->nodes_pp = &mt->nodes;
424 int yaz_marc_write_check(yaz_marc_t mt, WRBUF wr)
426 struct yaz_marc_node *n;
427 int identifier_length;
428 const char *leader = 0;
430 for (n = mt->nodes; n; n = n->next)
431 if (n->which == YAZ_MARC_LEADER)
433 leader = n->u.leader;
439 if (!atoi_n_check(leader+11, 1, &identifier_length))
442 for (n = mt->nodes; n; n = n->next)
446 case YAZ_MARC_COMMENT:
447 wrbuf_iconv_write(wr, mt->iconv_cd,
448 n->u.comment, strlen(n->u.comment));
449 wrbuf_puts(wr, "\n");
458 static size_t get_subfield_len(yaz_marc_t mt, const char *data,
459 int identifier_length)
461 /* if identifier length is 2 (most MARCs) or less (probably an error),
462 the code is a single character .. However we've
463 seen multibyte codes, so see how big it really is */
464 if (identifier_length > 2)
465 return identifier_length - 1;
467 return cdata_one_character(mt, data);
470 int yaz_marc_write_line(yaz_marc_t mt, WRBUF wr)
472 struct yaz_marc_node *n;
473 int identifier_length;
474 const char *leader = 0;
476 for (n = mt->nodes; n; n = n->next)
477 if (n->which == YAZ_MARC_LEADER)
479 leader = n->u.leader;
485 if (!atoi_n_check(leader+11, 1, &identifier_length))
488 for (n = mt->nodes; n; n = n->next)
490 struct yaz_marc_subfield *s;
493 case YAZ_MARC_DATAFIELD:
494 wrbuf_printf(wr, "%s %s", n->u.datafield.tag,
495 n->u.datafield.indicator);
496 for (s = n->u.datafield.subfields; s; s = s->next)
498 size_t using_code_len = get_subfield_len(mt, s->code_data,
501 wrbuf_puts (wr, mt->subfield_str);
502 wrbuf_iconv_write(wr, mt->iconv_cd, s->code_data,
504 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
505 wrbuf_iconv_puts(wr, mt->iconv_cd,
506 s->code_data + using_code_len);
507 marc_iconv_reset(mt, wr);
509 wrbuf_puts (wr, mt->endline_str);
511 case YAZ_MARC_CONTROLFIELD:
512 wrbuf_printf(wr, "%s", n->u.controlfield.tag);
513 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
514 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
515 marc_iconv_reset(mt, wr);
516 wrbuf_puts (wr, mt->endline_str);
518 case YAZ_MARC_COMMENT:
520 wrbuf_iconv_write(wr, mt->iconv_cd,
521 n->u.comment, strlen(n->u.comment));
522 marc_iconv_reset(mt, wr);
523 wrbuf_puts(wr, ")\n");
525 case YAZ_MARC_LEADER:
526 wrbuf_printf(wr, "%s\n", n->u.leader);
529 wrbuf_puts(wr, "\n");
533 int yaz_marc_write_trailer(yaz_marc_t mt, WRBUF wr)
535 if (mt->enable_collection == collection_second)
537 switch(mt->output_format)
539 case YAZ_MARC_MARCXML:
540 case YAZ_MARC_TMARCXML:
541 wrbuf_printf(wr, "</collection>\n");
543 case YAZ_MARC_XCHANGE:
544 wrbuf_printf(wr, "</collection>\n");
551 void yaz_marc_enable_collection(yaz_marc_t mt)
553 mt->enable_collection = collection_first;
556 int yaz_marc_write_mode(yaz_marc_t mt, WRBUF wr)
558 switch(mt->output_format)
561 return yaz_marc_write_line(mt, wr);
562 case YAZ_MARC_MARCXML:
563 case YAZ_MARC_TMARCXML:
564 return yaz_marc_write_marcxml(mt, wr);
565 case YAZ_MARC_XCHANGE:
566 return yaz_marc_write_marcxchange(mt, wr, 0, 0); /* no format, type */
567 case YAZ_MARC_ISO2709:
568 return yaz_marc_write_iso2709(mt, wr);
570 return yaz_marc_write_check(mt, wr);
575 /** \brief common MARC XML/Xchange writer
577 \param wr WRBUF output
578 \param ns XMLNS for the elements
579 \param format record format (e.g. "MARC21")
580 \param type record type (e.g. "Bibliographic")
582 static int yaz_marc_write_marcxml_ns1(yaz_marc_t mt, WRBUF wr,
587 struct yaz_marc_node *n;
588 int identifier_length;
589 const char *leader = 0;
591 for (n = mt->nodes; n; n = n->next)
592 if (n->which == YAZ_MARC_LEADER)
594 leader = n->u.leader;
600 if (!atoi_n_check(leader+11, 1, &identifier_length))
603 if (mt->enable_collection != no_collection)
605 if (mt->enable_collection == collection_first)
606 wrbuf_printf(wr, "<collection xmlns=\"%s\">\n", ns);
607 mt->enable_collection = collection_second;
608 wrbuf_printf(wr, "<record");
612 wrbuf_printf(wr, "<record xmlns=\"%s\"", ns);
615 wrbuf_printf(wr, " format=\"%.80s\"", format);
617 wrbuf_printf(wr, " type=\"%.80s\"", type);
618 wrbuf_printf(wr, ">\n");
619 for (n = mt->nodes; n; n = n->next)
621 struct yaz_marc_subfield *s;
625 case YAZ_MARC_DATAFIELD:
626 wrbuf_printf(wr, " <datafield tag=\"");
627 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
628 strlen(n->u.datafield.tag));
629 wrbuf_printf(wr, "\"");
630 if (n->u.datafield.indicator)
633 for (i = 0; n->u.datafield.indicator[i]; i++)
635 wrbuf_printf(wr, " ind%d=\"", i+1);
636 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
637 n->u.datafield.indicator+i, 1);
638 wrbuf_iconv_puts(wr, mt->iconv_cd, "\"");
641 wrbuf_printf(wr, ">\n");
642 for (s = n->u.datafield.subfields; s; s = s->next)
644 size_t using_code_len = get_subfield_len(mt, s->code_data,
646 wrbuf_iconv_puts(wr, mt->iconv_cd, " <subfield code=\"");
647 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
648 s->code_data, using_code_len);
649 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
650 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
651 s->code_data + using_code_len,
652 strlen(s->code_data + using_code_len));
653 marc_iconv_reset(mt, wr);
654 wrbuf_iconv_puts(wr, mt->iconv_cd, "</subfield>");
655 wrbuf_puts(wr, "\n");
657 wrbuf_printf(wr, " </datafield>\n");
659 case YAZ_MARC_CONTROLFIELD:
660 wrbuf_printf(wr, " <controlfield tag=\"");
661 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
662 strlen(n->u.controlfield.tag));
663 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
664 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
665 n->u.controlfield.data,
666 strlen(n->u.controlfield.data));
668 marc_iconv_reset(mt, wr);
669 wrbuf_iconv_puts(wr, mt->iconv_cd, "</controlfield>");
670 wrbuf_puts(wr, "\n");
672 case YAZ_MARC_COMMENT:
673 wrbuf_printf(wr, "<!-- ");
674 wrbuf_puts(wr, n->u.comment);
675 wrbuf_printf(wr, " -->\n");
677 case YAZ_MARC_LEADER:
678 wrbuf_printf(wr, " <leader>");
679 wrbuf_iconv_write_cdata(wr,
680 0 /* no charset conversion for leader */,
681 n->u.leader, strlen(n->u.leader));
682 wrbuf_printf(wr, "</leader>\n");
685 wrbuf_puts(wr, "</record>\n");
689 static int yaz_marc_write_marcxml_ns(yaz_marc_t mt, WRBUF wr,
694 if (mt->write_using_libxml2)
700 if (!mt->turbo_format)
701 ret = yaz_marc_write_xml(mt, &root_ptr, ns, format, type);
703 ret = yaz_marc_write_turbo_xml(mt, &root_ptr, ns, format, type);
707 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
710 xmlDocSetRootElement(doc, root_ptr);
711 xmlDocDumpMemory(doc, &buf_out, &len_out);
713 wrbuf_write(wr, (const char *) buf_out, len_out);
724 return yaz_marc_write_marcxml_ns1(mt, wr, ns, format, type);
727 int yaz_marc_write_marcxml(yaz_marc_t mt, WRBUF wr)
729 /* set leader 09 to 'a' for UNICODE */
730 /* http://www.loc.gov/marc/bibliographic/ecbdldrd.html#mrcblea */
731 if (!mt->leader_spec)
732 yaz_marc_modify_leader(mt, 9, "a");
733 char *name_space = "http://www.loc.gov/MARC21/slim";
734 if (mt->output_format == YAZ_MARC_TMARCXML)
735 name_space = "http://www.indexdata.com/MARC21/turboxml";
736 return yaz_marc_write_marcxml_ns(mt, wr, name_space,
740 int yaz_marc_write_marcxchange(yaz_marc_t mt, WRBUF wr,
744 return yaz_marc_write_marcxml_ns(mt, wr,
745 "info:lc/xmlns/marcxchange-v1",
751 void add_marc_datafield_turbo_xml(yaz_marc_t mt, struct yaz_marc_node *n, xmlNode *record_ptr, xmlNsPtr ns_record, WRBUF wr_cdata, int identifier_length)
754 struct yaz_marc_subfield *s;
755 int turbo = mt->turbo_format;
757 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
758 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
761 //TODO consider if safe
764 strncpy(field + 1, n->u.datafield.tag, 3);
766 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST field, 0);
768 if (n->u.datafield.indicator)
771 for (i = 0; n->u.datafield.indicator[i]; i++)
776 ind_val[0] = n->u.datafield.indicator[i];
779 sprintf(ind_str, "ind%d", i+1);
780 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
783 sprintf(ind_str, "i%d", i+1);
784 xmlNewTextChild(ptr, ns_record, BAD_CAST ind_str, BAD_CAST ind_val);
788 WRBUF subfield_name = wrbuf_alloc();
789 for (s = n->u.datafield.subfields; s; s = s->next)
791 xmlNode *ptr_subfield;
792 size_t using_code_len = get_subfield_len(mt, s->code_data,
794 wrbuf_rewind(wr_cdata);
795 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, s->code_data + using_code_len);
796 marc_iconv_reset(mt, wr_cdata);
799 ptr_subfield = xmlNewTextChild(
801 BAD_CAST "subfield", BAD_CAST wrbuf_cstr(wr_cdata));
802 wrbuf_rewind(wr_cdata);
803 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,s->code_data, using_code_len);
804 xmlNewProp(ptr_subfield, BAD_CAST "code",
805 BAD_CAST wrbuf_cstr(wr_cdata));
807 else { // Turbo format
808 wrbuf_rewind(subfield_name);
809 wrbuf_puts(subfield_name, "s");
810 // TODO Map special codes to something possible for XML ELEMENT names
811 if ((s->code_data[0] >= '0' && s->code_data[0] <= '9') ||
812 (s->code_data[0] >= 'a' && s->code_data[0] <= 'z') ||
813 (s->code_data[0] >= 'A' && s->code_data[0] <= 'Z'))
815 wrbuf_iconv_write(subfield_name, mt->iconv_cd,s->code_data, using_code_len);
818 char buffer[2*using_code_len + 1];
820 for (index = 0; index < using_code_len; index++) {
821 sprintf(buffer + 2*index, "%02X", (unsigned char) s->code_data[index] & 0xFF);
823 buffer[2*(index+1)] = 0;
824 wrbuf_puts(subfield_name, "-");
825 wrbuf_puts(subfield_name, buffer);
826 yaz_log(YLOG_WARN, "Using numeric value in element name: %s", buffer);
828 ptr_subfield = xmlNewTextChild(ptr, ns_record,
829 BAD_CAST wrbuf_cstr(subfield_name),
830 BAD_CAST wrbuf_cstr(wr_cdata));
833 wrbuf_destroy(subfield_name);
836 int yaz_marc_write_turbo_xml(yaz_marc_t mt, xmlNode **root_ptr,
841 struct yaz_marc_node *n;
842 int identifier_length;
843 const char *leader = 0;
847 int turbo = mt->turbo_format;
848 for (n = mt->nodes; n; n = n->next)
849 if (n->which == YAZ_MARC_LEADER)
851 leader = n->u.leader;
857 if (!atoi_n_check(leader+11, 1, &identifier_length))
860 wr_cdata = wrbuf_alloc();
862 record_ptr = xmlNewNode(0, BAD_CAST "record");
863 *root_ptr = record_ptr;
865 ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
866 xmlSetNs(record_ptr, ns_record);
869 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
871 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
872 for (n = mt->nodes; n; n = n->next)
874 struct yaz_marc_subfield *s;
879 case YAZ_MARC_DATAFIELD:
880 add_marc_datafield_turbo_xml(mt, n, record_ptr, ns_record, wr_cdata, identifier_length);
882 case YAZ_MARC_CONTROLFIELD:
883 wrbuf_rewind(wr_cdata);
884 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
885 marc_iconv_reset(mt, wr_cdata);
888 ptr = xmlNewTextChild(record_ptr, ns_record,
889 BAD_CAST "controlfield",
890 BAD_CAST wrbuf_cstr(wr_cdata));
891 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
894 // TODO required iconv?
897 strncpy(field + 1, n->u.controlfield.tag, 3);
899 ptr = xmlNewTextChild(record_ptr, ns_record,
901 BAD_CAST wrbuf_cstr(wr_cdata));
905 case YAZ_MARC_COMMENT:
906 ptr = xmlNewComment(BAD_CAST n->u.comment);
907 xmlAddChild(record_ptr, ptr);
909 case YAZ_MARC_LEADER:
911 char *field = "leader";
914 xmlNewTextChild(record_ptr, ns_record, BAD_CAST field,
915 BAD_CAST n->u.leader);
920 wrbuf_destroy(wr_cdata);
925 int yaz_marc_write_xml(yaz_marc_t mt, xmlNode **root_ptr,
930 struct yaz_marc_node *n;
931 int identifier_length;
932 const char *leader = 0;
937 for (n = mt->nodes; n; n = n->next)
938 if (n->which == YAZ_MARC_LEADER)
940 leader = n->u.leader;
946 if (!atoi_n_check(leader+11, 1, &identifier_length))
949 wr_cdata = wrbuf_alloc();
951 record_ptr = xmlNewNode(0, BAD_CAST "record");
952 *root_ptr = record_ptr;
954 ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
955 xmlSetNs(record_ptr, ns_record);
958 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
960 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
961 for (n = mt->nodes; n; n = n->next)
963 struct yaz_marc_subfield *s;
968 case YAZ_MARC_DATAFIELD:
969 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
970 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
971 if (n->u.datafield.indicator)
974 for (i = 0; n->u.datafield.indicator[i]; i++)
979 sprintf(ind_str, "ind%d", i+1);
980 ind_val[0] = n->u.datafield.indicator[i];
982 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
985 for (s = n->u.datafield.subfields; s; s = s->next)
987 xmlNode *ptr_subfield;
988 size_t using_code_len = get_subfield_len(mt, s->code_data,
990 wrbuf_rewind(wr_cdata);
991 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd,
992 s->code_data + using_code_len);
993 marc_iconv_reset(mt, wr_cdata);
994 ptr_subfield = xmlNewTextChild(
996 BAD_CAST "subfield", BAD_CAST wrbuf_cstr(wr_cdata));
998 wrbuf_rewind(wr_cdata);
999 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,
1000 s->code_data, using_code_len);
1001 xmlNewProp(ptr_subfield, BAD_CAST "code",
1002 BAD_CAST wrbuf_cstr(wr_cdata));
1005 case YAZ_MARC_CONTROLFIELD:
1006 wrbuf_rewind(wr_cdata);
1007 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
1008 marc_iconv_reset(mt, wr_cdata);
1010 ptr = xmlNewTextChild(record_ptr, ns_record,
1011 BAD_CAST "controlfield",
1012 BAD_CAST wrbuf_cstr(wr_cdata));
1014 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
1016 case YAZ_MARC_COMMENT:
1017 ptr = xmlNewComment(BAD_CAST n->u.comment);
1018 xmlAddChild(record_ptr, ptr);
1020 case YAZ_MARC_LEADER:
1021 xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
1022 BAD_CAST n->u.leader);
1026 wrbuf_destroy(wr_cdata);
1035 int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
1037 struct yaz_marc_node *n;
1038 int indicator_length;
1039 int identifier_length;
1040 int length_data_entry;
1041 int length_starting;
1042 int length_implementation;
1043 int data_offset = 0;
1044 const char *leader = 0;
1045 WRBUF wr_dir, wr_head, wr_data_tmp;
1048 for (n = mt->nodes; n; n = n->next)
1049 if (n->which == YAZ_MARC_LEADER)
1050 leader = n->u.leader;
1054 if (!atoi_n_check(leader+10, 1, &indicator_length))
1056 if (!atoi_n_check(leader+11, 1, &identifier_length))
1058 if (!atoi_n_check(leader+20, 1, &length_data_entry))
1060 if (!atoi_n_check(leader+21, 1, &length_starting))
1062 if (!atoi_n_check(leader+22, 1, &length_implementation))
1065 wr_data_tmp = wrbuf_alloc();
1066 wr_dir = wrbuf_alloc();
1067 for (n = mt->nodes; n; n = n->next)
1069 int data_length = 0;
1070 struct yaz_marc_subfield *s;
1074 case YAZ_MARC_DATAFIELD:
1075 wrbuf_printf(wr_dir, "%.3s", n->u.datafield.tag);
1076 data_length += indicator_length;
1077 wrbuf_rewind(wr_data_tmp);
1078 for (s = n->u.datafield.subfields; s; s = s->next)
1080 /* write dummy IDFS + content */
1081 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
1082 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
1083 marc_iconv_reset(mt, wr_data_tmp);
1085 /* write dummy FS (makes MARC-8 to become ASCII) */
1086 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
1087 marc_iconv_reset(mt, wr_data_tmp);
1088 data_length += wrbuf_len(wr_data_tmp);
1090 case YAZ_MARC_CONTROLFIELD:
1091 wrbuf_printf(wr_dir, "%.3s", n->u.controlfield.tag);
1093 wrbuf_rewind(wr_data_tmp);
1094 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd,
1095 n->u.controlfield.data);
1096 marc_iconv_reset(mt, wr_data_tmp);
1097 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
1098 marc_iconv_reset(mt, wr_data_tmp);
1099 data_length += wrbuf_len(wr_data_tmp);
1101 case YAZ_MARC_COMMENT:
1103 case YAZ_MARC_LEADER:
1108 wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
1109 wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
1110 data_offset += data_length;
1113 /* mark end of directory */
1114 wrbuf_putc(wr_dir, ISO2709_FS);
1116 /* base address of data (comes after leader+directory) */
1117 base_address = 24 + wrbuf_len(wr_dir);
1119 wr_head = wrbuf_alloc();
1121 /* write record length */
1122 wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
1123 /* from "original" leader */
1124 wrbuf_write(wr_head, leader+5, 7);
1125 /* base address of data */
1126 wrbuf_printf(wr_head, "%05d", base_address);
1127 /* from "original" leader */
1128 wrbuf_write(wr_head, leader+17, 7);
1130 wrbuf_write(wr, wrbuf_buf(wr_head), 24);
1131 wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
1132 wrbuf_destroy(wr_head);
1133 wrbuf_destroy(wr_dir);
1134 wrbuf_destroy(wr_data_tmp);
1136 for (n = mt->nodes; n; n = n->next)
1138 struct yaz_marc_subfield *s;
1142 case YAZ_MARC_DATAFIELD:
1143 wrbuf_printf(wr, "%.*s", indicator_length,
1144 n->u.datafield.indicator);
1145 for (s = n->u.datafield.subfields; s; s = s->next)
1147 wrbuf_putc(wr, ISO2709_IDFS);
1148 wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
1149 marc_iconv_reset(mt, wr);
1151 wrbuf_putc(wr, ISO2709_FS);
1153 case YAZ_MARC_CONTROLFIELD:
1154 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
1155 marc_iconv_reset(mt, wr);
1156 wrbuf_putc(wr, ISO2709_FS);
1158 case YAZ_MARC_COMMENT:
1160 case YAZ_MARC_LEADER:
1164 wrbuf_printf(wr, "%c", ISO2709_RS);
1169 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
1171 int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
1174 s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
1176 return -1; /* error */
1177 return r; /* OK, return length > 0 */
1180 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
1181 const char **result, size_t *rsize)
1185 wrbuf_rewind(mt->m_wr);
1186 r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
1188 *result = wrbuf_cstr(mt->m_wr);
1190 *rsize = wrbuf_len(mt->m_wr);
1194 void yaz_marc_set_read_format(yaz_marc_t mt, int format)
1197 mt->input_format = format;
1200 int yaz_marc_get_read_format(yaz_marc_t mt)
1203 return mt->input_format;
1208 void yaz_marc_set_write_format(yaz_marc_t mt, int format)
1211 mt->output_format = format;
1214 int yaz_marc_get_write_format(yaz_marc_t mt)
1217 return mt->output_format;
1223 * Deprecated, use yaz_marc_set_write_format
1225 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
1228 mt->output_format = xmlmode;
1233 void yaz_marc_debug(yaz_marc_t mt, int level)
1239 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
1244 yaz_iconv_t yaz_marc_get_iconv(yaz_marc_t mt)
1246 return mt->iconv_cd;
1249 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
1251 struct yaz_marc_node *n;
1253 for (n = mt->nodes; n; n = n->next)
1254 if (n->which == YAZ_MARC_LEADER)
1256 leader = n->u.leader;
1257 memcpy(leader+off, str, strlen(str));
1262 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
1264 xfree(mt->leader_spec);
1265 mt->leader_spec = 0;
1268 char dummy_leader[24];
1269 if (marc_exec_leader(leader_spec, dummy_leader, 24))
1271 mt->leader_spec = xstrdup(leader_spec);
1276 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
1278 const char *cp = leader_spec;
1283 int no_read = 0, no = 0;
1285 no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1286 if (no < 2 || no_read < 3)
1288 if (pos < 0 || (size_t) pos >= size)
1293 const char *vp = strchr(val+1, '\'');
1299 if (len + pos > size)
1301 memcpy(leader + pos, val+1, len);
1303 else if (*val >= '0' && *val <= '9')
1319 int yaz_marc_decode_formatstr(const char *arg)
1322 if (!strcmp(arg, "marc"))
1323 mode = YAZ_MARC_ISO2709;
1324 if (!strcmp(arg, "marcxml"))
1325 mode = YAZ_MARC_MARCXML;
1326 if (!strcmp(arg, "tmarcxml"))
1327 mode = YAZ_MARC_TMARCXML;
1328 if (!strcmp(arg, "marcxchange"))
1329 mode = YAZ_MARC_XCHANGE;
1330 if (!strcmp(arg, "line"))
1331 mode = YAZ_MARC_LINE;
1335 void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
1337 mt->write_using_libxml2 = enable;
1340 void yaz_marc_write_turbo_format(yaz_marc_t mt, int enable)
1342 mt->turbo_format = enable;
1345 int yaz_marc_is_turbo_format(yaz_marc_t mt)
1347 return mt->turbo_format;
1354 * c-file-style: "Stroustrup"
1355 * indent-tabs-mode: nil
1357 * vim: shiftwidth=4 tabstop=8 expandtab