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 */
92 int write_using_libxml2;
93 enum yaz_collection_state enable_collection;
98 struct yaz_marc_node *nodes;
99 struct yaz_marc_node **nodes_pp;
100 struct yaz_marc_subfield **subfield_pp;
103 yaz_marc_t yaz_marc_create(void)
105 yaz_marc_t mt = (yaz_marc_t) xmalloc(sizeof(*mt));
106 mt->xml = YAZ_MARC_LINE;
108 mt->write_using_libxml2 = 0;
109 mt->enable_collection = no_collection;
110 mt->m_wr = wrbuf_alloc();
113 strcpy(mt->subfield_str, " $");
114 strcpy(mt->endline_str, "\n");
116 mt->nmem = nmem_create();
121 void yaz_marc_destroy(yaz_marc_t mt)
125 nmem_destroy(mt->nmem);
126 wrbuf_destroy(mt->m_wr);
127 xfree(mt->leader_spec);
131 NMEM yaz_marc_get_nmem(yaz_marc_t mt)
136 static void marc_iconv_reset(yaz_marc_t mt, WRBUF wr)
138 wrbuf_iconv_reset(wr, mt->iconv_cd);
141 static int marc_exec_leader(const char *leader_spec, char *leader,
145 static struct yaz_marc_node *yaz_marc_add_node(yaz_marc_t mt)
147 struct yaz_marc_node *n = (struct yaz_marc_node *)
148 nmem_malloc(mt->nmem, sizeof(*n));
151 mt->nodes_pp = &n->next;
156 void yaz_marc_add_controlfield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
157 const xmlNode *ptr_data)
159 struct yaz_marc_node *n = yaz_marc_add_node(mt);
160 n->which = YAZ_MARC_CONTROLFIELD;
161 n->u.controlfield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
162 n->u.controlfield.data = nmem_text_node_cdata(ptr_data, mt->nmem);
167 void yaz_marc_add_comment(yaz_marc_t mt, char *comment)
169 struct yaz_marc_node *n = yaz_marc_add_node(mt);
170 n->which = YAZ_MARC_COMMENT;
171 n->u.comment = nmem_strdup(mt->nmem, comment);
174 void yaz_marc_cprintf(yaz_marc_t mt, const char *fmt, ...)
180 yaz_vsnprintf(buf, sizeof(buf)-1, fmt, ap);
181 yaz_marc_add_comment(mt, buf);
185 int yaz_marc_get_debug(yaz_marc_t mt)
190 void yaz_marc_add_leader(yaz_marc_t mt, const char *leader, size_t leader_len)
192 struct yaz_marc_node *n = yaz_marc_add_node(mt);
193 n->which = YAZ_MARC_LEADER;
194 n->u.leader = nmem_strdupn(mt->nmem, leader, leader_len);
195 marc_exec_leader(mt->leader_spec, n->u.leader, leader_len);
198 void yaz_marc_add_controlfield(yaz_marc_t mt, const char *tag,
199 const char *data, size_t data_len)
201 struct yaz_marc_node *n = yaz_marc_add_node(mt);
202 n->which = YAZ_MARC_CONTROLFIELD;
203 n->u.controlfield.tag = nmem_strdup(mt->nmem, tag);
204 n->u.controlfield.data = nmem_strdupn(mt->nmem, data, data_len);
210 sprintf(msg, "controlfield:");
211 for (i = 0; i < 16 && i < data_len; i++)
212 sprintf(msg + strlen(msg), " %02X", data[i] & 0xff);
214 sprintf(msg + strlen(msg), " ..");
215 yaz_marc_add_comment(mt, msg);
219 void yaz_marc_add_datafield(yaz_marc_t mt, const char *tag,
220 const char *indicator, size_t indicator_len)
222 struct yaz_marc_node *n = yaz_marc_add_node(mt);
223 n->which = YAZ_MARC_DATAFIELD;
224 n->u.datafield.tag = nmem_strdup(mt->nmem, tag);
225 n->u.datafield.indicator =
226 nmem_strdupn(mt->nmem, indicator, indicator_len);
227 n->u.datafield.subfields = 0;
229 /* make subfield_pp the current (last one) */
230 mt->subfield_pp = &n->u.datafield.subfields;
234 void yaz_marc_add_datafield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
235 const char *indicator, size_t indicator_len)
237 struct yaz_marc_node *n = yaz_marc_add_node(mt);
238 n->which = YAZ_MARC_DATAFIELD;
239 n->u.datafield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
240 n->u.datafield.indicator =
241 nmem_strdupn(mt->nmem, indicator, indicator_len);
242 n->u.datafield.subfields = 0;
244 /* make subfield_pp the current (last one) */
245 mt->subfield_pp = &n->u.datafield.subfields;
249 void yaz_marc_add_subfield(yaz_marc_t mt,
250 const char *code_data, size_t code_data_len)
257 sprintf(msg, "subfield:");
258 for (i = 0; i < 16 && i < code_data_len; i++)
259 sprintf(msg + strlen(msg), " %02X", code_data[i] & 0xff);
260 if (i < code_data_len)
261 sprintf(msg + strlen(msg), " ..");
262 yaz_marc_add_comment(mt, msg);
267 struct yaz_marc_subfield *n = (struct yaz_marc_subfield *)
268 nmem_malloc(mt->nmem, sizeof(*n));
269 n->code_data = nmem_strdupn(mt->nmem, code_data, code_data_len);
271 /* mark subfield_pp to point to this one, so we append here next */
272 *mt->subfield_pp = n;
273 mt->subfield_pp = &n->next;
277 void yaz_marc_set_leader(yaz_marc_t mt, const char *leader_c,
278 int *indicator_length,
279 int *identifier_length,
281 int *length_data_entry,
282 int *length_starting,
283 int *length_implementation)
287 memcpy(leader, leader_c, 24);
289 if (!atoi_n_check(leader+10, 1, indicator_length))
292 "Indicator length at offset 10 should hold a digit."
295 *indicator_length = 2;
297 if (!atoi_n_check(leader+11, 1, identifier_length))
300 "Identifier length at offset 11 should hold a digit."
303 *identifier_length = 2;
305 if (!atoi_n_check(leader+12, 5, base_address))
308 "Base address at offsets 12..16 should hold a number."
312 if (!atoi_n_check(leader+20, 1, length_data_entry))
315 "Length data entry at offset 20 should hold a digit."
317 *length_data_entry = 4;
320 if (!atoi_n_check(leader+21, 1, length_starting))
323 "Length starting at offset 21 should hold a digit."
325 *length_starting = 5;
328 if (!atoi_n_check(leader+22, 1, length_implementation))
331 "Length implementation at offset 22 should hold a digit."
333 *length_implementation = 0;
339 yaz_marc_cprintf(mt, "Indicator length %5d", *indicator_length);
340 yaz_marc_cprintf(mt, "Identifier length %5d", *identifier_length);
341 yaz_marc_cprintf(mt, "Base address %5d", *base_address);
342 yaz_marc_cprintf(mt, "Length data entry %5d", *length_data_entry);
343 yaz_marc_cprintf(mt, "Length starting %5d", *length_starting);
344 yaz_marc_cprintf(mt, "Length implementation %5d", *length_implementation);
346 yaz_marc_add_leader(mt, leader, 24);
349 void yaz_marc_subfield_str(yaz_marc_t mt, const char *s)
351 strncpy(mt->subfield_str, s, sizeof(mt->subfield_str)-1);
352 mt->subfield_str[sizeof(mt->subfield_str)-1] = '\0';
355 void yaz_marc_endline_str(yaz_marc_t mt, const char *s)
357 strncpy(mt->endline_str, s, sizeof(mt->endline_str)-1);
358 mt->endline_str[sizeof(mt->endline_str)-1] = '\0';
361 /* try to guess how many bytes the identifier really is! */
362 static size_t cdata_one_character(yaz_marc_t mt, const char *buf)
367 for (i = 1; i<5; i++)
370 size_t outbytesleft = sizeof(outbuf);
372 const char *inp = buf;
374 size_t inbytesleft = i;
375 size_t r = yaz_iconv(mt->iconv_cd, (char**) &inp, &inbytesleft,
376 &outp, &outbytesleft);
377 if (r != (size_t) (-1))
378 return i; /* got a complete sequence */
380 return 1; /* giving up */
382 return 1; /* we don't know */
385 void yaz_marc_reset(yaz_marc_t mt)
387 nmem_reset(mt->nmem);
389 mt->nodes_pp = &mt->nodes;
393 int yaz_marc_write_check(yaz_marc_t mt, WRBUF wr)
395 struct yaz_marc_node *n;
396 int identifier_length;
397 const char *leader = 0;
399 for (n = mt->nodes; n; n = n->next)
400 if (n->which == YAZ_MARC_LEADER)
402 leader = n->u.leader;
408 if (!atoi_n_check(leader+11, 1, &identifier_length))
411 for (n = mt->nodes; n; n = n->next)
415 case YAZ_MARC_COMMENT:
416 wrbuf_iconv_write(wr, mt->iconv_cd,
417 n->u.comment, strlen(n->u.comment));
418 wrbuf_puts(wr, "\n");
427 static size_t get_subfield_len(yaz_marc_t mt, const char *data,
428 int identifier_length)
430 /* if identifier length is 2 (most MARCs) or less (probably an error),
431 the code is a single character .. However we've
432 seen multibyte codes, so see how big it really is */
433 if (identifier_length > 2)
434 return identifier_length - 1;
436 return cdata_one_character(mt, data);
439 int yaz_marc_write_line(yaz_marc_t mt, WRBUF wr)
441 struct yaz_marc_node *n;
442 int identifier_length;
443 const char *leader = 0;
445 for (n = mt->nodes; n; n = n->next)
446 if (n->which == YAZ_MARC_LEADER)
448 leader = n->u.leader;
454 if (!atoi_n_check(leader+11, 1, &identifier_length))
457 for (n = mt->nodes; n; n = n->next)
459 struct yaz_marc_subfield *s;
462 case YAZ_MARC_DATAFIELD:
463 wrbuf_printf(wr, "%s %s", n->u.datafield.tag,
464 n->u.datafield.indicator);
465 for (s = n->u.datafield.subfields; s; s = s->next)
467 size_t using_code_len = get_subfield_len(mt, s->code_data,
470 wrbuf_puts (wr, mt->subfield_str);
471 wrbuf_iconv_write(wr, mt->iconv_cd, s->code_data,
473 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
474 wrbuf_iconv_puts(wr, mt->iconv_cd,
475 s->code_data + using_code_len);
476 marc_iconv_reset(mt, wr);
478 wrbuf_puts (wr, mt->endline_str);
480 case YAZ_MARC_CONTROLFIELD:
481 wrbuf_printf(wr, "%s", n->u.controlfield.tag);
482 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
483 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
484 marc_iconv_reset(mt, wr);
485 wrbuf_puts (wr, mt->endline_str);
487 case YAZ_MARC_COMMENT:
489 wrbuf_iconv_write(wr, mt->iconv_cd,
490 n->u.comment, strlen(n->u.comment));
491 marc_iconv_reset(mt, wr);
492 wrbuf_puts(wr, ")\n");
494 case YAZ_MARC_LEADER:
495 wrbuf_printf(wr, "%s\n", n->u.leader);
498 wrbuf_puts(wr, "\n");
502 int yaz_marc_write_trailer(yaz_marc_t mt, WRBUF wr)
504 if (mt->enable_collection == collection_second)
508 case YAZ_MARC_MARCXML:
509 wrbuf_printf(wr, "</collection>\n");
511 case YAZ_MARC_XCHANGE:
512 wrbuf_printf(wr, "</collection>\n");
519 void yaz_marc_enable_collection(yaz_marc_t mt)
521 mt->enable_collection = collection_first;
524 int yaz_marc_write_mode(yaz_marc_t mt, WRBUF wr)
529 return yaz_marc_write_line(mt, wr);
530 case YAZ_MARC_MARCXML:
531 return yaz_marc_write_marcxml(mt, wr);
532 case YAZ_MARC_XCHANGE:
533 return yaz_marc_write_marcxchange(mt, wr, 0, 0); /* no format, type */
534 case YAZ_MARC_ISO2709:
535 return yaz_marc_write_iso2709(mt, wr);
537 return yaz_marc_write_check(mt, wr);
542 /** \brief common MARC XML/Xchange writer
544 \param wr WRBUF output
545 \param ns XMLNS for the elements
546 \param format record format (e.g. "MARC21")
547 \param type record type (e.g. "Bibliographic")
549 static int yaz_marc_write_marcxml_ns1(yaz_marc_t mt, WRBUF wr,
554 struct yaz_marc_node *n;
555 int identifier_length;
556 const char *leader = 0;
558 for (n = mt->nodes; n; n = n->next)
559 if (n->which == YAZ_MARC_LEADER)
561 leader = n->u.leader;
567 if (!atoi_n_check(leader+11, 1, &identifier_length))
570 if (mt->enable_collection != no_collection)
572 if (mt->enable_collection == collection_first)
573 wrbuf_printf(wr, "<collection xmlns=\"%s\">\n", ns);
574 mt->enable_collection = collection_second;
575 wrbuf_printf(wr, "<record");
579 wrbuf_printf(wr, "<record xmlns=\"%s\"", ns);
582 wrbuf_printf(wr, " format=\"%.80s\"", format);
584 wrbuf_printf(wr, " type=\"%.80s\"", type);
585 wrbuf_printf(wr, ">\n");
586 for (n = mt->nodes; n; n = n->next)
588 struct yaz_marc_subfield *s;
592 case YAZ_MARC_DATAFIELD:
593 wrbuf_printf(wr, " <datafield tag=\"");
594 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
595 strlen(n->u.datafield.tag));
596 wrbuf_printf(wr, "\"");
597 if (n->u.datafield.indicator)
600 for (i = 0; n->u.datafield.indicator[i]; i++)
602 wrbuf_printf(wr, " ind%d=\"", i+1);
603 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
604 n->u.datafield.indicator+i, 1);
605 wrbuf_iconv_puts(wr, mt->iconv_cd, "\"");
608 wrbuf_printf(wr, ">\n");
609 for (s = n->u.datafield.subfields; s; s = s->next)
611 size_t using_code_len = get_subfield_len(mt, s->code_data,
613 wrbuf_iconv_puts(wr, mt->iconv_cd, " <subfield code=\"");
614 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
615 s->code_data, using_code_len);
616 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
617 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
618 s->code_data + using_code_len,
619 strlen(s->code_data + using_code_len));
620 marc_iconv_reset(mt, wr);
621 wrbuf_iconv_puts(wr, mt->iconv_cd, "</subfield>");
622 wrbuf_puts(wr, "\n");
624 wrbuf_printf(wr, " </datafield>\n");
626 case YAZ_MARC_CONTROLFIELD:
627 wrbuf_printf(wr, " <controlfield tag=\"");
628 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
629 strlen(n->u.controlfield.tag));
630 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
631 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
632 n->u.controlfield.data,
633 strlen(n->u.controlfield.data));
635 marc_iconv_reset(mt, wr);
636 wrbuf_iconv_puts(wr, mt->iconv_cd, "</controlfield>");
637 wrbuf_puts(wr, "\n");
639 case YAZ_MARC_COMMENT:
640 wrbuf_printf(wr, "<!-- ");
641 wrbuf_puts(wr, n->u.comment);
642 wrbuf_printf(wr, " -->\n");
644 case YAZ_MARC_LEADER:
645 wrbuf_printf(wr, " <leader>");
646 wrbuf_iconv_write_cdata(wr,
647 0 /* no charset conversion for leader */,
648 n->u.leader, strlen(n->u.leader));
649 wrbuf_printf(wr, "</leader>\n");
652 wrbuf_puts(wr, "</record>\n");
656 static int yaz_marc_write_marcxml_ns(yaz_marc_t mt, WRBUF wr,
661 if (mt->write_using_libxml2)
667 ret = yaz_marc_write_xml(mt, &root_ptr, ns, format, type);
671 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
674 xmlDocSetRootElement(doc, root_ptr);
675 xmlDocDumpMemory(doc, &buf_out, &len_out);
677 wrbuf_write(wr, (const char *) buf_out, len_out);
688 return yaz_marc_write_marcxml_ns1(mt, wr, ns, format, type);
691 int yaz_marc_write_marcxml(yaz_marc_t mt, WRBUF wr)
693 /* set leader 09 to 'a' for UNICODE */
694 /* http://www.loc.gov/marc/bibliographic/ecbdldrd.html#mrcblea */
695 if (!mt->leader_spec)
696 yaz_marc_modify_leader(mt, 9, "a");
697 return yaz_marc_write_marcxml_ns(mt, wr, "http://www.loc.gov/MARC21/slim",
701 int yaz_marc_write_marcxchange(yaz_marc_t mt, WRBUF wr,
705 return yaz_marc_write_marcxml_ns(mt, wr,
706 "info:lc/xmlns/marcxchange-v1",
712 void addMarcDatafield(xmlNode *record_ptr, xmlNameSpace *ns_record, const char* datafield, int turbo, WRBUF wr_cdata)
715 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
716 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
719 char *field = "datXXX";
720 sprintf(field +3,"%s", n->u.datafield.tag);
721 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "dat", 0);
722 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
724 if (n->u.datafield.indicator)
727 for (i = 0; n->u.datafield.indicator[i]; i++)
732 sprintf(ind_str, "ind%d", i+1);
733 ind_val[0] = n->u.datafield.indicator[i];
735 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
738 for (s = n->u.datafield.subfields; s; s = s->next)
740 xmlNode *ptr_subfield;
741 size_t using_code_len = get_subfield_len(mt, s->code_data,
743 wrbuf_rewind(wr_cdata);
744 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd,
745 s->code_data + using_code_len);
746 marc_iconv_reset(mt, wr_cdata);
747 ptr_subfield = xmlNewTextChild(
749 BAD_CAST "subfield", BAD_CAST wrbuf_cstr(wr_cdata));
751 wrbuf_rewind(wr_cdata);
752 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,
753 s->code_data, using_code_len);
754 xmlNewProp(ptr_subfield, BAD_CAST "code",
755 BAD_CAST wrbuf_cstr(wr_cdata));
759 int yaz_marc_write_xml(yaz_marc_t mt, xmlNode **root_ptr,
764 struct yaz_marc_node *n;
765 int identifier_length;
766 const char *leader = 0;
771 for (n = mt->nodes; n; n = n->next)
772 if (n->which == YAZ_MARC_LEADER)
774 leader = n->u.leader;
780 if (!atoi_n_check(leader+11, 1, &identifier_length))
783 wr_cdata = wrbuf_alloc();
785 record_ptr = xmlNewNode(0, BAD_CAST "record");
786 *root_ptr = record_ptr;
788 ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
789 xmlSetNs(record_ptr, ns_record);
792 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
794 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
795 for (n = mt->nodes; n; n = n->next)
797 struct yaz_marc_subfield *s;
802 case YAZ_MARC_DATAFIELD:
803 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
804 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
805 if (n->u.datafield.indicator)
808 for (i = 0; n->u.datafield.indicator[i]; i++)
813 sprintf(ind_str, "ind%d", i+1);
814 ind_val[0] = n->u.datafield.indicator[i];
816 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
819 for (s = n->u.datafield.subfields; s; s = s->next)
821 xmlNode *ptr_subfield;
822 size_t using_code_len = get_subfield_len(mt, s->code_data,
824 wrbuf_rewind(wr_cdata);
825 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd,
826 s->code_data + using_code_len);
827 marc_iconv_reset(mt, wr_cdata);
828 ptr_subfield = xmlNewTextChild(
830 BAD_CAST "subfield", BAD_CAST wrbuf_cstr(wr_cdata));
832 wrbuf_rewind(wr_cdata);
833 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,
834 s->code_data, using_code_len);
835 xmlNewProp(ptr_subfield, BAD_CAST "code",
836 BAD_CAST wrbuf_cstr(wr_cdata));
839 case YAZ_MARC_CONTROLFIELD:
840 wrbuf_rewind(wr_cdata);
841 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
842 marc_iconv_reset(mt, wr_cdata);
844 ptr = xmlNewTextChild(record_ptr, ns_record,
845 BAD_CAST "controlfield",
846 BAD_CAST wrbuf_cstr(wr_cdata));
848 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
850 case YAZ_MARC_COMMENT:
851 ptr = xmlNewComment(BAD_CAST n->u.comment);
852 xmlAddChild(record_ptr, ptr);
854 case YAZ_MARC_LEADER:
855 xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
856 BAD_CAST n->u.leader);
860 wrbuf_destroy(wr_cdata);
865 int yaz_marc_write_turbo_xml(yaz_marc_t mt, xmlNode **root_ptr,
870 struct yaz_marc_node *n;
871 int identifier_length;
872 const char *leader = 0;
877 for (n = mt->nodes; n; n = n->next)
878 if (n->which == YAZ_MARC_LEADER)
880 leader = n->u.leader;
886 if (!atoi_n_check(leader+11, 1, &identifier_length))
889 wr_cdata = wrbuf_alloc();
891 record_ptr = xmlNewNode(0, BAD_CAST "record");
892 *root_ptr = record_ptr;
894 ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
895 xmlSetNs(record_ptr, ns_record);
898 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
900 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
901 for (n = mt->nodes; n; n = n->next)
903 struct yaz_marc_subfield *s;
908 case YAZ_MARC_DATAFIELD:
910 addMarcDatafield(record_ptr, ns_record, datafield, turbo, wr_cdata);
912 case YAZ_MARC_CONTROLFIELD:
913 wrbuf_rewind(wr_cdata);
914 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
915 marc_iconv_reset(mt, wr_cdata);
917 ptr = xmlNewTextChild(record_ptr, ns_record,
918 BAD_CAST "controlfield",
919 BAD_CAST wrbuf_cstr(wr_cdata));
921 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
923 case YAZ_MARC_COMMENT:
924 ptr = xmlNewComment(BAD_CAST n->u.comment);
925 xmlAddChild(record_ptr, ptr);
927 case YAZ_MARC_LEADER:
928 xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
929 BAD_CAST n->u.leader);
933 wrbuf_destroy(wr_cdata);
940 int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
942 struct yaz_marc_node *n;
943 int indicator_length;
944 int identifier_length;
945 int length_data_entry;
947 int length_implementation;
949 const char *leader = 0;
950 WRBUF wr_dir, wr_head, wr_data_tmp;
953 for (n = mt->nodes; n; n = n->next)
954 if (n->which == YAZ_MARC_LEADER)
955 leader = n->u.leader;
959 if (!atoi_n_check(leader+10, 1, &indicator_length))
961 if (!atoi_n_check(leader+11, 1, &identifier_length))
963 if (!atoi_n_check(leader+20, 1, &length_data_entry))
965 if (!atoi_n_check(leader+21, 1, &length_starting))
967 if (!atoi_n_check(leader+22, 1, &length_implementation))
970 wr_data_tmp = wrbuf_alloc();
971 wr_dir = wrbuf_alloc();
972 for (n = mt->nodes; n; n = n->next)
975 struct yaz_marc_subfield *s;
979 case YAZ_MARC_DATAFIELD:
980 wrbuf_printf(wr_dir, "%.3s", n->u.datafield.tag);
981 data_length += indicator_length;
982 wrbuf_rewind(wr_data_tmp);
983 for (s = n->u.datafield.subfields; s; s = s->next)
985 /* write dummy IDFS + content */
986 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
987 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
988 marc_iconv_reset(mt, wr_data_tmp);
990 /* write dummy FS (makes MARC-8 to become ASCII) */
991 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
992 marc_iconv_reset(mt, wr_data_tmp);
993 data_length += wrbuf_len(wr_data_tmp);
995 case YAZ_MARC_CONTROLFIELD:
996 wrbuf_printf(wr_dir, "%.3s", n->u.controlfield.tag);
998 wrbuf_rewind(wr_data_tmp);
999 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd,
1000 n->u.controlfield.data);
1001 marc_iconv_reset(mt, wr_data_tmp);
1002 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
1003 marc_iconv_reset(mt, wr_data_tmp);
1004 data_length += wrbuf_len(wr_data_tmp);
1006 case YAZ_MARC_COMMENT:
1008 case YAZ_MARC_LEADER:
1013 wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
1014 wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
1015 data_offset += data_length;
1018 /* mark end of directory */
1019 wrbuf_putc(wr_dir, ISO2709_FS);
1021 /* base address of data (comes after leader+directory) */
1022 base_address = 24 + wrbuf_len(wr_dir);
1024 wr_head = wrbuf_alloc();
1026 /* write record length */
1027 wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
1028 /* from "original" leader */
1029 wrbuf_write(wr_head, leader+5, 7);
1030 /* base address of data */
1031 wrbuf_printf(wr_head, "%05d", base_address);
1032 /* from "original" leader */
1033 wrbuf_write(wr_head, leader+17, 7);
1035 wrbuf_write(wr, wrbuf_buf(wr_head), 24);
1036 wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
1037 wrbuf_destroy(wr_head);
1038 wrbuf_destroy(wr_dir);
1039 wrbuf_destroy(wr_data_tmp);
1041 for (n = mt->nodes; n; n = n->next)
1043 struct yaz_marc_subfield *s;
1047 case YAZ_MARC_DATAFIELD:
1048 wrbuf_printf(wr, "%.*s", indicator_length,
1049 n->u.datafield.indicator);
1050 for (s = n->u.datafield.subfields; s; s = s->next)
1052 wrbuf_putc(wr, ISO2709_IDFS);
1053 wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
1054 marc_iconv_reset(mt, wr);
1056 wrbuf_putc(wr, ISO2709_FS);
1058 case YAZ_MARC_CONTROLFIELD:
1059 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
1060 marc_iconv_reset(mt, wr);
1061 wrbuf_putc(wr, ISO2709_FS);
1063 case YAZ_MARC_COMMENT:
1065 case YAZ_MARC_LEADER:
1069 wrbuf_printf(wr, "%c", ISO2709_RS);
1074 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
1076 int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
1079 s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
1081 return -1; /* error */
1082 return r; /* OK, return length > 0 */
1085 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
1086 const char **result, size_t *rsize)
1090 wrbuf_rewind(mt->m_wr);
1091 r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
1093 *result = wrbuf_cstr(mt->m_wr);
1095 *rsize = wrbuf_len(mt->m_wr);
1099 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
1105 void yaz_marc_debug(yaz_marc_t mt, int level)
1111 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
1116 yaz_iconv_t yaz_marc_get_iconv(yaz_marc_t mt)
1118 return mt->iconv_cd;
1121 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
1123 struct yaz_marc_node *n;
1125 for (n = mt->nodes; n; n = n->next)
1126 if (n->which == YAZ_MARC_LEADER)
1128 leader = n->u.leader;
1129 memcpy(leader+off, str, strlen(str));
1134 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
1136 xfree(mt->leader_spec);
1137 mt->leader_spec = 0;
1140 char dummy_leader[24];
1141 if (marc_exec_leader(leader_spec, dummy_leader, 24))
1143 mt->leader_spec = xstrdup(leader_spec);
1148 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
1150 const char *cp = leader_spec;
1155 int no_read = 0, no = 0;
1157 no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1158 if (no < 2 || no_read < 3)
1160 if (pos < 0 || (size_t) pos >= size)
1165 const char *vp = strchr(val+1, '\'');
1171 if (len + pos > size)
1173 memcpy(leader + pos, val+1, len);
1175 else if (*val >= '0' && *val <= '9')
1191 int yaz_marc_decode_formatstr(const char *arg)
1194 if (!strcmp(arg, "marc"))
1195 mode = YAZ_MARC_ISO2709;
1196 if (!strcmp(arg, "marcxml"))
1197 mode = YAZ_MARC_MARCXML;
1198 if (!strcmp(arg, "marcxchange"))
1199 mode = YAZ_MARC_XCHANGE;
1200 if (!strcmp(arg, "line"))
1201 mode = YAZ_MARC_LINE;
1205 void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
1207 mt->write_using_libxml2 = enable;
1213 * c-file-style: "Stroustrup"
1214 * indent-tabs-mode: nil
1216 * vim: shiftwidth=4 tabstop=8 expandtab