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);
169 void yaz_marc_add_comment(yaz_marc_t mt, char *comment)
171 struct yaz_marc_node *n = yaz_marc_add_node(mt);
172 n->which = YAZ_MARC_COMMENT;
173 n->u.comment = nmem_strdup(mt->nmem, comment);
176 void yaz_marc_cprintf(yaz_marc_t mt, const char *fmt, ...)
182 yaz_vsnprintf(buf, sizeof(buf)-1, fmt, ap);
183 yaz_marc_add_comment(mt, buf);
187 int yaz_marc_get_debug(yaz_marc_t mt)
192 void yaz_marc_add_leader(yaz_marc_t mt, const char *leader, size_t leader_len)
194 struct yaz_marc_node *n = yaz_marc_add_node(mt);
195 n->which = YAZ_MARC_LEADER;
196 n->u.leader = nmem_strdupn(mt->nmem, leader, leader_len);
197 marc_exec_leader(mt->leader_spec, n->u.leader, leader_len);
200 void yaz_marc_add_controlfield(yaz_marc_t mt, const char *tag,
201 const char *data, size_t data_len)
203 struct yaz_marc_node *n = yaz_marc_add_node(mt);
204 n->which = YAZ_MARC_CONTROLFIELD;
205 n->u.controlfield.tag = nmem_strdup(mt->nmem, tag);
206 n->u.controlfield.data = nmem_strdupn(mt->nmem, data, data_len);
212 sprintf(msg, "controlfield:");
213 for (i = 0; i < 16 && i < data_len; i++)
214 sprintf(msg + strlen(msg), " %02X", data[i] & 0xff);
216 sprintf(msg + strlen(msg), " ..");
217 yaz_marc_add_comment(mt, msg);
221 void yaz_marc_add_datafield(yaz_marc_t mt, const char *tag,
222 const char *indicator, size_t indicator_len)
224 struct yaz_marc_node *n = yaz_marc_add_node(mt);
225 n->which = YAZ_MARC_DATAFIELD;
226 n->u.datafield.tag = nmem_strdup(mt->nmem, tag);
227 n->u.datafield.indicator =
228 nmem_strdupn(mt->nmem, indicator, indicator_len);
229 n->u.datafield.subfields = 0;
231 /* make subfield_pp the current (last one) */
232 mt->subfield_pp = &n->u.datafield.subfields;
236 void yaz_marc_add_datafield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
237 const char *indicator, size_t indicator_len)
239 struct yaz_marc_node *n = yaz_marc_add_node(mt);
240 n->which = YAZ_MARC_DATAFIELD;
241 n->u.datafield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
242 n->u.datafield.indicator =
243 nmem_strdupn(mt->nmem, indicator, indicator_len);
244 n->u.datafield.subfields = 0;
246 /* make subfield_pp the current (last one) */
247 mt->subfield_pp = &n->u.datafield.subfields;
250 struct yaz_marc_node* yaz_marc_add_datafield_turbo_xml(yaz_marc_t mt, char *tag_value)
252 struct yaz_marc_node *n = yaz_marc_add_node(mt);
253 n->which = YAZ_MARC_DATAFIELD;
254 n->u.datafield.tag = tag_value;
255 n->u.datafield.indicator = 0;
256 n->u.datafield.subfields = 0;
258 /* make subfield_pp the current (last one) */
259 mt->subfield_pp = &n->u.datafield.subfields;
263 void yaz_marc_datafield_set_indicators(struct yaz_marc_node *n, char *indicator)
265 n->u.datafield.indicator = indicator;
270 void yaz_marc_add_subfield(yaz_marc_t mt,
271 const char *code_data, size_t code_data_len)
278 sprintf(msg, "subfield:");
279 for (i = 0; i < 16 && i < code_data_len; i++)
280 sprintf(msg + strlen(msg), " %02X", code_data[i] & 0xff);
281 if (i < code_data_len)
282 sprintf(msg + strlen(msg), " ..");
283 yaz_marc_add_comment(mt, msg);
288 struct yaz_marc_subfield *n = (struct yaz_marc_subfield *)
289 nmem_malloc(mt->nmem, sizeof(*n));
290 n->code_data = nmem_strdupn(mt->nmem, code_data, code_data_len);
292 /* mark subfield_pp to point to this one, so we append here next */
293 *mt->subfield_pp = n;
294 mt->subfield_pp = &n->next;
298 void yaz_marc_set_leader(yaz_marc_t mt, const char *leader_c,
299 int *indicator_length,
300 int *identifier_length,
302 int *length_data_entry,
303 int *length_starting,
304 int *length_implementation)
308 memcpy(leader, leader_c, 24);
310 if (!atoi_n_check(leader+10, 1, indicator_length))
313 "Indicator length at offset 10 should hold a digit."
316 *indicator_length = 2;
318 if (!atoi_n_check(leader+11, 1, identifier_length))
321 "Identifier length at offset 11 should hold a digit."
324 *identifier_length = 2;
326 if (!atoi_n_check(leader+12, 5, base_address))
329 "Base address at offsets 12..16 should hold a number."
333 if (!atoi_n_check(leader+20, 1, length_data_entry))
336 "Length data entry at offset 20 should hold a digit."
338 *length_data_entry = 4;
341 if (!atoi_n_check(leader+21, 1, length_starting))
344 "Length starting at offset 21 should hold a digit."
346 *length_starting = 5;
349 if (!atoi_n_check(leader+22, 1, length_implementation))
352 "Length implementation at offset 22 should hold a digit."
354 *length_implementation = 0;
360 yaz_marc_cprintf(mt, "Indicator length %5d", *indicator_length);
361 yaz_marc_cprintf(mt, "Identifier length %5d", *identifier_length);
362 yaz_marc_cprintf(mt, "Base address %5d", *base_address);
363 yaz_marc_cprintf(mt, "Length data entry %5d", *length_data_entry);
364 yaz_marc_cprintf(mt, "Length starting %5d", *length_starting);
365 yaz_marc_cprintf(mt, "Length implementation %5d", *length_implementation);
367 yaz_marc_add_leader(mt, leader, 24);
370 void yaz_marc_subfield_str(yaz_marc_t mt, const char *s)
372 strncpy(mt->subfield_str, s, sizeof(mt->subfield_str)-1);
373 mt->subfield_str[sizeof(mt->subfield_str)-1] = '\0';
376 void yaz_marc_endline_str(yaz_marc_t mt, const char *s)
378 strncpy(mt->endline_str, s, sizeof(mt->endline_str)-1);
379 mt->endline_str[sizeof(mt->endline_str)-1] = '\0';
382 /* try to guess how many bytes the identifier really is! */
383 static size_t cdata_one_character(yaz_marc_t mt, const char *buf)
388 for (i = 1; i<5; i++)
391 size_t outbytesleft = sizeof(outbuf);
393 const char *inp = buf;
395 size_t inbytesleft = i;
396 size_t r = yaz_iconv(mt->iconv_cd, (char**) &inp, &inbytesleft,
397 &outp, &outbytesleft);
398 if (r != (size_t) (-1))
399 return i; /* got a complete sequence */
401 return 1; /* giving up */
403 return 1; /* we don't know */
406 void yaz_marc_reset(yaz_marc_t mt)
408 nmem_reset(mt->nmem);
410 mt->nodes_pp = &mt->nodes;
414 int yaz_marc_write_check(yaz_marc_t mt, WRBUF wr)
416 struct yaz_marc_node *n;
417 int identifier_length;
418 const char *leader = 0;
420 for (n = mt->nodes; n; n = n->next)
421 if (n->which == YAZ_MARC_LEADER)
423 leader = n->u.leader;
429 if (!atoi_n_check(leader+11, 1, &identifier_length))
432 for (n = mt->nodes; n; n = n->next)
436 case YAZ_MARC_COMMENT:
437 wrbuf_iconv_write(wr, mt->iconv_cd,
438 n->u.comment, strlen(n->u.comment));
439 wrbuf_puts(wr, "\n");
448 static size_t get_subfield_len(yaz_marc_t mt, const char *data,
449 int identifier_length)
451 /* if identifier length is 2 (most MARCs) or less (probably an error),
452 the code is a single character .. However we've
453 seen multibyte codes, so see how big it really is */
454 if (identifier_length > 2)
455 return identifier_length - 1;
457 return cdata_one_character(mt, data);
460 int yaz_marc_write_line(yaz_marc_t mt, WRBUF wr)
462 struct yaz_marc_node *n;
463 int identifier_length;
464 const char *leader = 0;
466 for (n = mt->nodes; n; n = n->next)
467 if (n->which == YAZ_MARC_LEADER)
469 leader = n->u.leader;
475 if (!atoi_n_check(leader+11, 1, &identifier_length))
478 for (n = mt->nodes; n; n = n->next)
480 struct yaz_marc_subfield *s;
483 case YAZ_MARC_DATAFIELD:
484 wrbuf_printf(wr, "%s %s", n->u.datafield.tag,
485 n->u.datafield.indicator);
486 for (s = n->u.datafield.subfields; s; s = s->next)
488 size_t using_code_len = get_subfield_len(mt, s->code_data,
491 wrbuf_puts (wr, mt->subfield_str);
492 wrbuf_iconv_write(wr, mt->iconv_cd, s->code_data,
494 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
495 wrbuf_iconv_puts(wr, mt->iconv_cd,
496 s->code_data + using_code_len);
497 marc_iconv_reset(mt, wr);
499 wrbuf_puts (wr, mt->endline_str);
501 case YAZ_MARC_CONTROLFIELD:
502 wrbuf_printf(wr, "%s", n->u.controlfield.tag);
503 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
504 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
505 marc_iconv_reset(mt, wr);
506 wrbuf_puts (wr, mt->endline_str);
508 case YAZ_MARC_COMMENT:
510 wrbuf_iconv_write(wr, mt->iconv_cd,
511 n->u.comment, strlen(n->u.comment));
512 marc_iconv_reset(mt, wr);
513 wrbuf_puts(wr, ")\n");
515 case YAZ_MARC_LEADER:
516 wrbuf_printf(wr, "%s\n", n->u.leader);
519 wrbuf_puts(wr, "\n");
523 int yaz_marc_write_trailer(yaz_marc_t mt, WRBUF wr)
525 if (mt->enable_collection == collection_second)
527 switch(mt->output_format)
529 case YAZ_MARC_MARCXML:
530 wrbuf_printf(wr, "</collection>\n");
532 case YAZ_MARC_XCHANGE:
533 wrbuf_printf(wr, "</collection>\n");
540 void yaz_marc_enable_collection(yaz_marc_t mt)
542 mt->enable_collection = collection_first;
545 int yaz_marc_write_mode(yaz_marc_t mt, WRBUF wr)
547 switch(mt->output_format)
550 return yaz_marc_write_line(mt, wr);
551 case YAZ_MARC_MARCXML:
552 case YAZ_MARC_TMARCXML:
553 return yaz_marc_write_marcxml(mt, wr);
554 case YAZ_MARC_XCHANGE:
555 return yaz_marc_write_marcxchange(mt, wr, 0, 0); /* no format, type */
556 case YAZ_MARC_ISO2709:
557 return yaz_marc_write_iso2709(mt, wr);
559 return yaz_marc_write_check(mt, wr);
564 /** \brief common MARC XML/Xchange writer
566 \param wr WRBUF output
567 \param ns XMLNS for the elements
568 \param format record format (e.g. "MARC21")
569 \param type record type (e.g. "Bibliographic")
571 static int yaz_marc_write_marcxml_ns1(yaz_marc_t mt, WRBUF wr,
576 struct yaz_marc_node *n;
577 int identifier_length;
578 const char *leader = 0;
580 for (n = mt->nodes; n; n = n->next)
581 if (n->which == YAZ_MARC_LEADER)
583 leader = n->u.leader;
589 if (!atoi_n_check(leader+11, 1, &identifier_length))
592 if (mt->enable_collection != no_collection)
594 if (mt->enable_collection == collection_first)
595 wrbuf_printf(wr, "<collection xmlns=\"%s\">\n", ns);
596 mt->enable_collection = collection_second;
597 wrbuf_printf(wr, "<record");
601 wrbuf_printf(wr, "<record xmlns=\"%s\"", ns);
604 wrbuf_printf(wr, " format=\"%.80s\"", format);
606 wrbuf_printf(wr, " type=\"%.80s\"", type);
607 wrbuf_printf(wr, ">\n");
608 for (n = mt->nodes; n; n = n->next)
610 struct yaz_marc_subfield *s;
614 case YAZ_MARC_DATAFIELD:
615 wrbuf_printf(wr, " <datafield tag=\"");
616 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
617 strlen(n->u.datafield.tag));
618 wrbuf_printf(wr, "\"");
619 if (n->u.datafield.indicator)
622 for (i = 0; n->u.datafield.indicator[i]; i++)
624 wrbuf_printf(wr, " ind%d=\"", i+1);
625 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
626 n->u.datafield.indicator+i, 1);
627 wrbuf_iconv_puts(wr, mt->iconv_cd, "\"");
630 wrbuf_printf(wr, ">\n");
631 for (s = n->u.datafield.subfields; s; s = s->next)
633 size_t using_code_len = get_subfield_len(mt, s->code_data,
635 wrbuf_iconv_puts(wr, mt->iconv_cd, " <subfield code=\"");
636 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
637 s->code_data, using_code_len);
638 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
639 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
640 s->code_data + using_code_len,
641 strlen(s->code_data + using_code_len));
642 marc_iconv_reset(mt, wr);
643 wrbuf_iconv_puts(wr, mt->iconv_cd, "</subfield>");
644 wrbuf_puts(wr, "\n");
646 wrbuf_printf(wr, " </datafield>\n");
648 case YAZ_MARC_CONTROLFIELD:
649 wrbuf_printf(wr, " <controlfield tag=\"");
650 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
651 strlen(n->u.controlfield.tag));
652 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
653 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
654 n->u.controlfield.data,
655 strlen(n->u.controlfield.data));
657 marc_iconv_reset(mt, wr);
658 wrbuf_iconv_puts(wr, mt->iconv_cd, "</controlfield>");
659 wrbuf_puts(wr, "\n");
661 case YAZ_MARC_COMMENT:
662 wrbuf_printf(wr, "<!-- ");
663 wrbuf_puts(wr, n->u.comment);
664 wrbuf_printf(wr, " -->\n");
666 case YAZ_MARC_LEADER:
667 wrbuf_printf(wr, " <leader>");
668 wrbuf_iconv_write_cdata(wr,
669 0 /* no charset conversion for leader */,
670 n->u.leader, strlen(n->u.leader));
671 wrbuf_printf(wr, "</leader>\n");
674 wrbuf_puts(wr, "</record>\n");
678 static int yaz_marc_write_marcxml_ns(yaz_marc_t mt, WRBUF wr,
683 if (mt->write_using_libxml2)
689 if (!mt->turbo_format)
690 ret = yaz_marc_write_xml(mt, &root_ptr, ns, format, type);
692 ret = yaz_marc_write_turbo_xml(mt, &root_ptr, ns, format, type);
696 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
699 xmlDocSetRootElement(doc, root_ptr);
700 xmlDocDumpMemory(doc, &buf_out, &len_out);
702 wrbuf_write(wr, (const char *) buf_out, len_out);
713 return yaz_marc_write_marcxml_ns1(mt, wr, ns, format, type);
716 int yaz_marc_write_marcxml(yaz_marc_t mt, WRBUF wr)
718 /* set leader 09 to 'a' for UNICODE */
719 /* http://www.loc.gov/marc/bibliographic/ecbdldrd.html#mrcblea */
720 if (!mt->leader_spec)
721 yaz_marc_modify_leader(mt, 9, "a");
722 char *name_space = "http://www.loc.gov/MARC21/slim";
723 if (mt->output_format == YAZ_MARC_TMARCXML)
724 name_space = "http://www.indexdata.com/MARC21/turboxml";
725 return yaz_marc_write_marcxml_ns(mt, wr, name_space,
729 int yaz_marc_write_marcxchange(yaz_marc_t mt, WRBUF wr,
733 return yaz_marc_write_marcxml_ns(mt, wr,
734 "info:lc/xmlns/marcxchange-v1",
740 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)
743 struct yaz_marc_subfield *s;
744 int turbo = mt->turbo_format;
746 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
747 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
750 //TODO consider if safe
753 strncpy(field + 1, n->u.datafield.tag, 3);
754 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST field, 0);
756 if (n->u.datafield.indicator)
759 for (i = 0; n->u.datafield.indicator[i]; i++)
764 ind_val[0] = n->u.datafield.indicator[i];
767 sprintf(ind_str, "ind%d", i+1);
768 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
771 sprintf(ind_str, "i%d", i+1);
772 xmlNewTextChild(ptr, ns_record, BAD_CAST ind_str, BAD_CAST ind_val);
776 WRBUF subfield_name = wrbuf_alloc();
777 for (s = n->u.datafield.subfields; s; s = s->next)
779 xmlNode *ptr_subfield;
780 size_t using_code_len = get_subfield_len(mt, s->code_data,
782 wrbuf_rewind(wr_cdata);
783 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, s->code_data + using_code_len);
784 marc_iconv_reset(mt, wr_cdata);
787 ptr_subfield = xmlNewTextChild(
789 BAD_CAST "subfield", BAD_CAST wrbuf_cstr(wr_cdata));
790 wrbuf_rewind(wr_cdata);
791 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,s->code_data, using_code_len);
792 xmlNewProp(ptr_subfield, BAD_CAST "code",
793 BAD_CAST wrbuf_cstr(wr_cdata));
795 else { // Turbo format
796 wrbuf_rewind(subfield_name);
797 wrbuf_puts(subfield_name, "s");
798 // TODO Map special codes to something possible for XML ELEMENT names
799 if ((s->code_data[0] >= '0' && s->code_data[0] <= '9') ||
800 (s->code_data[0] >= 'a' && s->code_data[0] <= 'z') ||
801 (s->code_data[0] >= 'A' && s->code_data[0] <= 'Z'))
803 wrbuf_iconv_write(subfield_name, mt->iconv_cd,s->code_data, using_code_len);
806 char buffer[2*using_code_len + 1];
808 for (index = 0; index < using_code_len; index++) {
809 sprintf(buffer + 2*index, "%02X", (unsigned char) s->code_data[index] & 0xFF);
811 buffer[2*(index+1)] = 0;
812 wrbuf_puts(subfield_name, "-");
813 wrbuf_puts(subfield_name, buffer);
814 yaz_log(YLOG_WARN, "Using numeric value in element name: %s", buffer);
816 ptr_subfield = xmlNewTextChild(ptr, ns_record,
817 BAD_CAST wrbuf_cstr(subfield_name),
818 BAD_CAST wrbuf_cstr(wr_cdata));
821 wrbuf_destroy(subfield_name);
824 int yaz_marc_write_turbo_xml(yaz_marc_t mt, xmlNode **root_ptr,
829 struct yaz_marc_node *n;
830 int identifier_length;
831 const char *leader = 0;
835 int turbo = mt->turbo_format;
836 for (n = mt->nodes; n; n = n->next)
837 if (n->which == YAZ_MARC_LEADER)
839 leader = n->u.leader;
845 if (!atoi_n_check(leader+11, 1, &identifier_length))
848 wr_cdata = wrbuf_alloc();
850 record_ptr = xmlNewNode(0, BAD_CAST "record");
851 *root_ptr = record_ptr;
853 ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
854 xmlSetNs(record_ptr, ns_record);
857 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
859 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
860 for (n = mt->nodes; n; n = n->next)
862 struct yaz_marc_subfield *s;
867 case YAZ_MARC_DATAFIELD:
868 add_marc_datafield_turbo_xml(mt, n, record_ptr, ns_record, wr_cdata, identifier_length);
870 case YAZ_MARC_CONTROLFIELD:
871 wrbuf_rewind(wr_cdata);
872 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
873 marc_iconv_reset(mt, wr_cdata);
876 ptr = xmlNewTextChild(record_ptr, ns_record,
877 BAD_CAST "controlfield",
878 BAD_CAST wrbuf_cstr(wr_cdata));
879 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
882 // TODO required iconv?
885 strncpy(field + 1, n->u.controlfield.tag, 3);
886 ptr = xmlNewTextChild(record_ptr, ns_record,
888 BAD_CAST wrbuf_cstr(wr_cdata));
892 case YAZ_MARC_COMMENT:
893 ptr = xmlNewComment(BAD_CAST n->u.comment);
894 xmlAddChild(record_ptr, ptr);
896 case YAZ_MARC_LEADER:
898 char *field = "leader";
901 xmlNewTextChild(record_ptr, ns_record, BAD_CAST field,
902 BAD_CAST n->u.leader);
907 wrbuf_destroy(wr_cdata);
912 int yaz_marc_write_xml(yaz_marc_t mt, xmlNode **root_ptr,
917 struct yaz_marc_node *n;
918 int identifier_length;
919 const char *leader = 0;
924 for (n = mt->nodes; n; n = n->next)
925 if (n->which == YAZ_MARC_LEADER)
927 leader = n->u.leader;
933 if (!atoi_n_check(leader+11, 1, &identifier_length))
936 wr_cdata = wrbuf_alloc();
938 record_ptr = xmlNewNode(0, BAD_CAST "record");
939 *root_ptr = record_ptr;
941 ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
942 xmlSetNs(record_ptr, ns_record);
945 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
947 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
948 for (n = mt->nodes; n; n = n->next)
950 struct yaz_marc_subfield *s;
955 case YAZ_MARC_DATAFIELD:
956 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
957 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
958 if (n->u.datafield.indicator)
961 for (i = 0; n->u.datafield.indicator[i]; i++)
966 sprintf(ind_str, "ind%d", i+1);
967 ind_val[0] = n->u.datafield.indicator[i];
969 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
972 for (s = n->u.datafield.subfields; s; s = s->next)
974 xmlNode *ptr_subfield;
975 size_t using_code_len = get_subfield_len(mt, s->code_data,
977 wrbuf_rewind(wr_cdata);
978 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd,
979 s->code_data + using_code_len);
980 marc_iconv_reset(mt, wr_cdata);
981 ptr_subfield = xmlNewTextChild(
983 BAD_CAST "subfield", BAD_CAST wrbuf_cstr(wr_cdata));
985 wrbuf_rewind(wr_cdata);
986 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,
987 s->code_data, using_code_len);
988 xmlNewProp(ptr_subfield, BAD_CAST "code",
989 BAD_CAST wrbuf_cstr(wr_cdata));
992 case YAZ_MARC_CONTROLFIELD:
993 wrbuf_rewind(wr_cdata);
994 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
995 marc_iconv_reset(mt, wr_cdata);
997 ptr = xmlNewTextChild(record_ptr, ns_record,
998 BAD_CAST "controlfield",
999 BAD_CAST wrbuf_cstr(wr_cdata));
1001 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
1003 case YAZ_MARC_COMMENT:
1004 ptr = xmlNewComment(BAD_CAST n->u.comment);
1005 xmlAddChild(record_ptr, ptr);
1007 case YAZ_MARC_LEADER:
1008 xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
1009 BAD_CAST n->u.leader);
1013 wrbuf_destroy(wr_cdata);
1022 int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
1024 struct yaz_marc_node *n;
1025 int indicator_length;
1026 int identifier_length;
1027 int length_data_entry;
1028 int length_starting;
1029 int length_implementation;
1030 int data_offset = 0;
1031 const char *leader = 0;
1032 WRBUF wr_dir, wr_head, wr_data_tmp;
1035 for (n = mt->nodes; n; n = n->next)
1036 if (n->which == YAZ_MARC_LEADER)
1037 leader = n->u.leader;
1041 if (!atoi_n_check(leader+10, 1, &indicator_length))
1043 if (!atoi_n_check(leader+11, 1, &identifier_length))
1045 if (!atoi_n_check(leader+20, 1, &length_data_entry))
1047 if (!atoi_n_check(leader+21, 1, &length_starting))
1049 if (!atoi_n_check(leader+22, 1, &length_implementation))
1052 wr_data_tmp = wrbuf_alloc();
1053 wr_dir = wrbuf_alloc();
1054 for (n = mt->nodes; n; n = n->next)
1056 int data_length = 0;
1057 struct yaz_marc_subfield *s;
1061 case YAZ_MARC_DATAFIELD:
1062 wrbuf_printf(wr_dir, "%.3s", n->u.datafield.tag);
1063 data_length += indicator_length;
1064 wrbuf_rewind(wr_data_tmp);
1065 for (s = n->u.datafield.subfields; s; s = s->next)
1067 /* write dummy IDFS + content */
1068 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
1069 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
1070 marc_iconv_reset(mt, wr_data_tmp);
1072 /* write dummy FS (makes MARC-8 to become ASCII) */
1073 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
1074 marc_iconv_reset(mt, wr_data_tmp);
1075 data_length += wrbuf_len(wr_data_tmp);
1077 case YAZ_MARC_CONTROLFIELD:
1078 wrbuf_printf(wr_dir, "%.3s", n->u.controlfield.tag);
1080 wrbuf_rewind(wr_data_tmp);
1081 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd,
1082 n->u.controlfield.data);
1083 marc_iconv_reset(mt, wr_data_tmp);
1084 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
1085 marc_iconv_reset(mt, wr_data_tmp);
1086 data_length += wrbuf_len(wr_data_tmp);
1088 case YAZ_MARC_COMMENT:
1090 case YAZ_MARC_LEADER:
1095 wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
1096 wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
1097 data_offset += data_length;
1100 /* mark end of directory */
1101 wrbuf_putc(wr_dir, ISO2709_FS);
1103 /* base address of data (comes after leader+directory) */
1104 base_address = 24 + wrbuf_len(wr_dir);
1106 wr_head = wrbuf_alloc();
1108 /* write record length */
1109 wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
1110 /* from "original" leader */
1111 wrbuf_write(wr_head, leader+5, 7);
1112 /* base address of data */
1113 wrbuf_printf(wr_head, "%05d", base_address);
1114 /* from "original" leader */
1115 wrbuf_write(wr_head, leader+17, 7);
1117 wrbuf_write(wr, wrbuf_buf(wr_head), 24);
1118 wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
1119 wrbuf_destroy(wr_head);
1120 wrbuf_destroy(wr_dir);
1121 wrbuf_destroy(wr_data_tmp);
1123 for (n = mt->nodes; n; n = n->next)
1125 struct yaz_marc_subfield *s;
1129 case YAZ_MARC_DATAFIELD:
1130 wrbuf_printf(wr, "%.*s", indicator_length,
1131 n->u.datafield.indicator);
1132 for (s = n->u.datafield.subfields; s; s = s->next)
1134 wrbuf_putc(wr, ISO2709_IDFS);
1135 wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
1136 marc_iconv_reset(mt, wr);
1138 wrbuf_putc(wr, ISO2709_FS);
1140 case YAZ_MARC_CONTROLFIELD:
1141 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
1142 marc_iconv_reset(mt, wr);
1143 wrbuf_putc(wr, ISO2709_FS);
1145 case YAZ_MARC_COMMENT:
1147 case YAZ_MARC_LEADER:
1151 wrbuf_printf(wr, "%c", ISO2709_RS);
1156 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
1158 int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
1161 s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
1163 return -1; /* error */
1164 return r; /* OK, return length > 0 */
1167 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
1168 const char **result, size_t *rsize)
1172 wrbuf_rewind(mt->m_wr);
1173 r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
1175 *result = wrbuf_cstr(mt->m_wr);
1177 *rsize = wrbuf_len(mt->m_wr);
1181 void yaz_marc_set_read_format(yaz_marc_t mt, int format)
1184 mt->input_format = format;
1187 int yaz_marc_get_read_format(yaz_marc_t mt)
1190 return mt->input_format;
1195 void yaz_marc_set_write_format(yaz_marc_t mt, int format)
1198 mt->output_format = format;
1201 int yaz_marc_get_write_format(yaz_marc_t mt)
1204 return mt->output_format;
1210 * Deprecated, use yaz_marc_set_write_format
1212 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
1215 mt->output_format = xmlmode;
1220 void yaz_marc_debug(yaz_marc_t mt, int level)
1226 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
1231 yaz_iconv_t yaz_marc_get_iconv(yaz_marc_t mt)
1233 return mt->iconv_cd;
1236 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
1238 struct yaz_marc_node *n;
1240 for (n = mt->nodes; n; n = n->next)
1241 if (n->which == YAZ_MARC_LEADER)
1243 leader = n->u.leader;
1244 memcpy(leader+off, str, strlen(str));
1249 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
1251 xfree(mt->leader_spec);
1252 mt->leader_spec = 0;
1255 char dummy_leader[24];
1256 if (marc_exec_leader(leader_spec, dummy_leader, 24))
1258 mt->leader_spec = xstrdup(leader_spec);
1263 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
1265 const char *cp = leader_spec;
1270 int no_read = 0, no = 0;
1272 no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1273 if (no < 2 || no_read < 3)
1275 if (pos < 0 || (size_t) pos >= size)
1280 const char *vp = strchr(val+1, '\'');
1286 if (len + pos > size)
1288 memcpy(leader + pos, val+1, len);
1290 else if (*val >= '0' && *val <= '9')
1306 int yaz_marc_decode_formatstr(const char *arg)
1309 if (!strcmp(arg, "marc"))
1310 mode = YAZ_MARC_ISO2709;
1311 if (!strcmp(arg, "marcxml"))
1312 mode = YAZ_MARC_MARCXML;
1313 if (!strcmp(arg, "tmarcxml"))
1314 mode = YAZ_MARC_TMARCXML;
1315 if (!strcmp(arg, "marcxchange"))
1316 mode = YAZ_MARC_XCHANGE;
1317 if (!strcmp(arg, "line"))
1318 mode = YAZ_MARC_LINE;
1322 void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
1324 mt->write_using_libxml2 = enable;
1327 void yaz_marc_write_turbo_format(yaz_marc_t mt, int enable)
1329 mt->turbo_format = enable;
1332 int yaz_marc_is_turbo_format(yaz_marc_t mt)
1334 return mt->turbo_format;
1341 * c-file-style: "Stroustrup"
1342 * indent-tabs-mode: nil
1344 * vim: shiftwidth=4 tabstop=8 expandtab