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->output_format = 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,
143 static int yaz_marc_write_xml_turbo_xml(yaz_marc_t mt, xmlNode **root_ptr,
148 static struct yaz_marc_node *yaz_marc_add_node(yaz_marc_t mt)
150 struct yaz_marc_node *n = (struct yaz_marc_node *)
151 nmem_malloc(mt->nmem, sizeof(*n));
154 mt->nodes_pp = &n->next;
159 void yaz_marc_add_controlfield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
160 const xmlNode *ptr_data)
162 struct yaz_marc_node *n = yaz_marc_add_node(mt);
163 n->which = YAZ_MARC_CONTROLFIELD;
164 n->u.controlfield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
165 n->u.controlfield.data = nmem_text_node_cdata(ptr_data, mt->nmem);
168 void yaz_marc_add_controlfield_xml2(yaz_marc_t mt, char *tag,
169 const xmlNode *ptr_data)
171 struct yaz_marc_node *n = yaz_marc_add_node(mt);
172 n->which = YAZ_MARC_CONTROLFIELD;
173 n->u.controlfield.tag = tag;
174 n->u.controlfield.data = nmem_text_node_cdata(ptr_data, mt->nmem);
180 void yaz_marc_add_comment(yaz_marc_t mt, char *comment)
182 struct yaz_marc_node *n = yaz_marc_add_node(mt);
183 n->which = YAZ_MARC_COMMENT;
184 n->u.comment = nmem_strdup(mt->nmem, comment);
187 void yaz_marc_cprintf(yaz_marc_t mt, const char *fmt, ...)
193 yaz_vsnprintf(buf, sizeof(buf)-1, fmt, ap);
194 yaz_marc_add_comment(mt, buf);
198 int yaz_marc_get_debug(yaz_marc_t mt)
203 void yaz_marc_add_leader(yaz_marc_t mt, const char *leader, size_t leader_len)
205 struct yaz_marc_node *n = yaz_marc_add_node(mt);
206 n->which = YAZ_MARC_LEADER;
207 n->u.leader = nmem_strdupn(mt->nmem, leader, leader_len);
208 marc_exec_leader(mt->leader_spec, n->u.leader, leader_len);
211 void yaz_marc_add_controlfield(yaz_marc_t mt, const char *tag,
212 const char *data, size_t data_len)
214 struct yaz_marc_node *n = yaz_marc_add_node(mt);
215 n->which = YAZ_MARC_CONTROLFIELD;
216 n->u.controlfield.tag = nmem_strdup(mt->nmem, tag);
217 n->u.controlfield.data = nmem_strdupn(mt->nmem, data, data_len);
223 sprintf(msg, "controlfield:");
224 for (i = 0; i < 16 && i < data_len; i++)
225 sprintf(msg + strlen(msg), " %02X", data[i] & 0xff);
227 sprintf(msg + strlen(msg), " ..");
228 yaz_marc_add_comment(mt, msg);
232 void yaz_marc_add_datafield(yaz_marc_t mt, const char *tag,
233 const char *indicator, size_t indicator_len)
235 struct yaz_marc_node *n = yaz_marc_add_node(mt);
236 n->which = YAZ_MARC_DATAFIELD;
237 n->u.datafield.tag = nmem_strdup(mt->nmem, tag);
238 n->u.datafield.indicator =
239 nmem_strdupn(mt->nmem, indicator, indicator_len);
240 n->u.datafield.subfields = 0;
242 /* make subfield_pp the current (last one) */
243 mt->subfield_pp = &n->u.datafield.subfields;
246 // Magic function: adds a attribute value to the element name if it is plain characters.
247 // if not, and if the attribute name is not null, it will append a attribute element with the value
248 // if attribute name is null it will return a non-zero value meaning it couldnt handle the value.
250 int element_name_append_attribute_value(yaz_marc_t mt, WRBUF buffer, const char *attribute_name, char *code_data, size_t code_len)
252 // TODO Map special codes to something possible for XML ELEMENT names
257 for (index = 0; index < code_len; index++)
259 if (!((code_data[index] >= '0' && code_data[index] <= '9') ||
260 (code_data[index] >= 'a' && code_data[index] <= 'z') ||
261 (code_data[index] >= 'A' && code_data[index] <= 'Z')))
265 if (encode && attribute_name)
266 wrbuf_printf(buffer, " %s=\"", attribute_name);
268 if (!encode || attribute_name)
269 wrbuf_iconv_write_cdata(buffer, mt->iconv_cd, code_data, code_len);
273 if (encode && attribute_name)
274 wrbuf_printf(buffer, "\""); // return error if we couldn't handle it.
279 void yaz_marc_add_datafield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
280 const char *indicator, size_t indicator_len)
282 struct yaz_marc_node *n = yaz_marc_add_node(mt);
283 n->which = YAZ_MARC_DATAFIELD;
284 n->u.datafield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
285 n->u.datafield.indicator =
286 nmem_strdupn(mt->nmem, indicator, indicator_len);
287 n->u.datafield.subfields = 0;
289 /* make subfield_pp the current (last one) */
290 mt->subfield_pp = &n->u.datafield.subfields;
293 void yaz_marc_add_datafield_xml2(yaz_marc_t mt, char *tag_value, char *indicators)
295 struct yaz_marc_node *n = yaz_marc_add_node(mt);
296 n->which = YAZ_MARC_DATAFIELD;
297 n->u.datafield.tag = tag_value;
298 n->u.datafield.indicator = indicators;
299 n->u.datafield.subfields = 0;
301 // make subfield_pp the current (last one)
302 mt->subfield_pp = &n->u.datafield.subfields;
305 void yaz_marc_datafield_set_indicators(struct yaz_marc_node *n, char *indicator)
307 n->u.datafield.indicator = indicator;
312 void yaz_marc_add_subfield(yaz_marc_t mt,
313 const char *code_data, size_t code_data_len)
320 sprintf(msg, "subfield:");
321 for (i = 0; i < 16 && i < code_data_len; i++)
322 sprintf(msg + strlen(msg), " %02X", code_data[i] & 0xff);
323 if (i < code_data_len)
324 sprintf(msg + strlen(msg), " ..");
325 yaz_marc_add_comment(mt, msg);
330 struct yaz_marc_subfield *n = (struct yaz_marc_subfield *)
331 nmem_malloc(mt->nmem, sizeof(*n));
332 n->code_data = nmem_strdupn(mt->nmem, code_data, code_data_len);
334 /* mark subfield_pp to point to this one, so we append here next */
335 *mt->subfield_pp = n;
336 mt->subfield_pp = &n->next;
340 void yaz_marc_set_leader(yaz_marc_t mt, const char *leader_c,
341 int *indicator_length,
342 int *identifier_length,
344 int *length_data_entry,
345 int *length_starting,
346 int *length_implementation)
350 memcpy(leader, leader_c, 24);
352 if (!atoi_n_check(leader+10, 1, indicator_length))
355 "Indicator length at offset 10 should hold a digit."
358 *indicator_length = 2;
360 if (!atoi_n_check(leader+11, 1, identifier_length))
363 "Identifier length at offset 11 should hold a digit."
366 *identifier_length = 2;
368 if (!atoi_n_check(leader+12, 5, base_address))
371 "Base address at offsets 12..16 should hold a number."
375 if (!atoi_n_check(leader+20, 1, length_data_entry))
378 "Length data entry at offset 20 should hold a digit."
380 *length_data_entry = 4;
383 if (!atoi_n_check(leader+21, 1, length_starting))
386 "Length starting at offset 21 should hold a digit."
388 *length_starting = 5;
391 if (!atoi_n_check(leader+22, 1, length_implementation))
394 "Length implementation at offset 22 should hold a digit."
396 *length_implementation = 0;
402 yaz_marc_cprintf(mt, "Indicator length %5d", *indicator_length);
403 yaz_marc_cprintf(mt, "Identifier length %5d", *identifier_length);
404 yaz_marc_cprintf(mt, "Base address %5d", *base_address);
405 yaz_marc_cprintf(mt, "Length data entry %5d", *length_data_entry);
406 yaz_marc_cprintf(mt, "Length starting %5d", *length_starting);
407 yaz_marc_cprintf(mt, "Length implementation %5d", *length_implementation);
409 yaz_marc_add_leader(mt, leader, 24);
412 void yaz_marc_subfield_str(yaz_marc_t mt, const char *s)
414 strncpy(mt->subfield_str, s, sizeof(mt->subfield_str)-1);
415 mt->subfield_str[sizeof(mt->subfield_str)-1] = '\0';
418 void yaz_marc_endline_str(yaz_marc_t mt, const char *s)
420 strncpy(mt->endline_str, s, sizeof(mt->endline_str)-1);
421 mt->endline_str[sizeof(mt->endline_str)-1] = '\0';
424 /* try to guess how many bytes the identifier really is! */
425 static size_t cdata_one_character(yaz_marc_t mt, const char *buf)
430 for (i = 1; i<5; i++)
433 size_t outbytesleft = sizeof(outbuf);
435 const char *inp = buf;
437 size_t inbytesleft = i;
438 size_t r = yaz_iconv(mt->iconv_cd, (char**) &inp, &inbytesleft,
439 &outp, &outbytesleft);
440 if (r != (size_t) (-1))
441 return i; /* got a complete sequence */
443 return 1; /* giving up */
445 return 1; /* we don't know */
448 void yaz_marc_reset(yaz_marc_t mt)
450 nmem_reset(mt->nmem);
452 mt->nodes_pp = &mt->nodes;
456 int yaz_marc_write_check(yaz_marc_t mt, WRBUF wr)
458 struct yaz_marc_node *n;
459 int identifier_length;
460 const char *leader = 0;
462 for (n = mt->nodes; n; n = n->next)
463 if (n->which == YAZ_MARC_LEADER)
465 leader = n->u.leader;
471 if (!atoi_n_check(leader+11, 1, &identifier_length))
474 for (n = mt->nodes; n; n = n->next)
478 case YAZ_MARC_COMMENT:
479 wrbuf_iconv_write(wr, mt->iconv_cd,
480 n->u.comment, strlen(n->u.comment));
481 wrbuf_puts(wr, "\n");
490 static size_t get_subfield_len(yaz_marc_t mt, const char *data,
491 int identifier_length)
493 /* if identifier length is 2 (most MARCs) or less (probably an error),
494 the code is a single character .. However we've
495 seen multibyte codes, so see how big it really is */
496 if (identifier_length > 2)
497 return identifier_length - 1;
499 return cdata_one_character(mt, data);
502 int yaz_marc_write_line(yaz_marc_t mt, WRBUF wr)
504 struct yaz_marc_node *n;
505 int identifier_length;
506 const char *leader = 0;
508 for (n = mt->nodes; n; n = n->next)
509 if (n->which == YAZ_MARC_LEADER)
511 leader = n->u.leader;
517 if (!atoi_n_check(leader+11, 1, &identifier_length))
520 for (n = mt->nodes; n; n = n->next)
522 struct yaz_marc_subfield *s;
525 case YAZ_MARC_DATAFIELD:
526 wrbuf_printf(wr, "%s %s", n->u.datafield.tag,
527 n->u.datafield.indicator);
528 for (s = n->u.datafield.subfields; s; s = s->next)
530 size_t using_code_len = get_subfield_len(mt, s->code_data,
533 wrbuf_puts (wr, mt->subfield_str);
534 wrbuf_iconv_write(wr, mt->iconv_cd, s->code_data,
536 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
537 wrbuf_iconv_puts(wr, mt->iconv_cd,
538 s->code_data + using_code_len);
539 marc_iconv_reset(mt, wr);
541 wrbuf_puts (wr, mt->endline_str);
543 case YAZ_MARC_CONTROLFIELD:
544 wrbuf_printf(wr, "%s", n->u.controlfield.tag);
545 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
546 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
547 marc_iconv_reset(mt, wr);
548 wrbuf_puts (wr, mt->endline_str);
550 case YAZ_MARC_COMMENT:
552 wrbuf_iconv_write(wr, mt->iconv_cd,
553 n->u.comment, strlen(n->u.comment));
554 marc_iconv_reset(mt, wr);
555 wrbuf_puts(wr, ")\n");
557 case YAZ_MARC_LEADER:
558 wrbuf_printf(wr, "%s\n", n->u.leader);
561 wrbuf_puts(wr, "\n");
565 int yaz_marc_write_trailer(yaz_marc_t mt, WRBUF wr)
567 if (mt->enable_collection == collection_second)
569 switch(mt->output_format)
571 case YAZ_MARC_MARCXML:
572 case YAZ_MARC_TMARCXML:
573 wrbuf_printf(wr, "</collection>\n");
575 case YAZ_MARC_XCHANGE:
576 wrbuf_printf(wr, "</collection>\n");
583 void yaz_marc_enable_collection(yaz_marc_t mt)
585 mt->enable_collection = collection_first;
588 int yaz_marc_write_mode(yaz_marc_t mt, WRBUF wr)
590 switch(mt->output_format)
593 return yaz_marc_write_line(mt, wr);
594 case YAZ_MARC_MARCXML:
595 return yaz_marc_write_marcxml(mt, wr);
596 case YAZ_MARC_TMARCXML:
597 return yaz_marc_write_turbo_xml(mt, wr);
598 case YAZ_MARC_XCHANGE:
599 return yaz_marc_write_marcxchange(mt, wr, 0, 0); /* no format, type */
600 case YAZ_MARC_ISO2709:
601 return yaz_marc_write_iso2709(mt, wr);
603 return yaz_marc_write_check(mt, wr);
608 static const char *record_name[2] = { "record", "r"};
609 static const char *leader_name[2] = { "leader", "l"};
610 static const char *controlfield_name[2] = { "controlfield", "c"};
611 static const char *datafield_name[2] = { "datafield", "d"};
612 static const char *indicator_name[2] = { "ind", "i"};
613 static const char *subfield_name[2] = { "subfield", "s"};
615 /** \brief common MARC XML/Xchange/turbomarc writer
617 \param wr WRBUF output
618 \param ns XMLNS for the elements
619 \param format record format (e.g. "MARC21")
620 \param type record type (e.g. "Bibliographic")
621 \param turbo =1 for turbomarc
625 static int yaz_marc_write_marcxml_wrbuf(yaz_marc_t mt, WRBUF wr,
631 struct yaz_marc_node *n;
632 int identifier_length;
633 const char *leader = 0;
635 for (n = mt->nodes; n; n = n->next)
636 if (n->which == YAZ_MARC_LEADER)
638 leader = n->u.leader;
644 if (!atoi_n_check(leader+11, 1, &identifier_length))
647 if (mt->enable_collection != no_collection)
649 if (mt->enable_collection == collection_first)
651 wrbuf_printf(wr, "<collection xmlns=\"%s\">\n", ns);
652 mt->enable_collection = collection_second;
654 wrbuf_printf(wr, "<%s", record_name[turbo]);
658 wrbuf_printf(wr, "<%s xmlns=\"%s\"", record_name[turbo], ns);
661 wrbuf_printf(wr, " format=\"%.80s\"", format);
663 wrbuf_printf(wr, " type=\"%.80s\"", type);
664 wrbuf_printf(wr, ">\n");
665 for (n = mt->nodes; n; n = n->next)
667 struct yaz_marc_subfield *s;
671 case YAZ_MARC_DATAFIELD:
673 wrbuf_printf(wr, " <%s", datafield_name[turbo]);
675 wrbuf_printf(wr, " tag=\"");
676 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
677 strlen(n->u.datafield.tag));
679 wrbuf_printf(wr, "\"");
680 if (n->u.datafield.indicator)
683 for (i = 0; n->u.datafield.indicator[i]; i++)
685 wrbuf_printf(wr, " %s%d=\"", indicator_name[turbo], i+1);
686 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
687 n->u.datafield.indicator+i, 1);
688 wrbuf_iconv_puts(wr, mt->iconv_cd, "\"");
691 wrbuf_printf(wr, ">\n");
692 for (s = n->u.datafield.subfields; s; s = s->next)
694 size_t using_code_len = get_subfield_len(mt, s->code_data,
696 wrbuf_printf(wr, " <%s", subfield_name[turbo]);
699 wrbuf_printf(wr, " code=\"");
700 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
701 s->code_data, using_code_len);
702 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
706 element_name_append_attribute_value(mt, wr, "code", s->code_data, using_code_len);
709 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
710 s->code_data + using_code_len,
711 strlen(s->code_data + using_code_len));
712 marc_iconv_reset(mt, wr);
713 wrbuf_printf(wr, "</%s", subfield_name[turbo]);
715 element_name_append_attribute_value(mt, wr, 0, s->code_data, using_code_len);
716 wrbuf_puts(wr, ">\n");
718 wrbuf_printf(wr, " </%s", datafield_name[turbo]);
721 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
722 strlen(n->u.datafield.tag));
723 wrbuf_printf(wr, ">\n");
725 case YAZ_MARC_CONTROLFIELD:
726 wrbuf_printf(wr, " <%s", controlfield_name[turbo]);
729 wrbuf_printf(wr, " tag=\"");
730 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
731 strlen(n->u.controlfield.tag));
732 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
736 //TODO convert special
737 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
738 strlen(n->u.controlfield.tag));
739 wrbuf_iconv_puts(wr, mt->iconv_cd, ">");
741 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
742 n->u.controlfield.data,
743 strlen(n->u.controlfield.data));
744 marc_iconv_reset(mt, wr);
745 wrbuf_printf(wr, "</%s", controlfield_name[turbo]);
746 //TODO convert special
748 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
749 strlen(n->u.controlfield.tag));
750 wrbuf_puts(wr, ">\n");
752 case YAZ_MARC_COMMENT:
753 wrbuf_printf(wr, "<!-- ");
754 wrbuf_puts(wr, n->u.comment);
755 wrbuf_printf(wr, " -->\n");
757 case YAZ_MARC_LEADER:
758 wrbuf_printf(wr, " <%s>", leader_name[turbo]);
759 wrbuf_iconv_write_cdata(wr,
760 0 , /* no charset conversion for leader */
761 n->u.leader, strlen(n->u.leader));
762 wrbuf_printf(wr, "</%s>\n", leader_name[turbo]);
765 wrbuf_printf(wr, "</%s>\n", record_name[turbo]);
769 static int yaz_marc_write_marcxml_ns(yaz_marc_t mt, WRBUF wr,
775 if (mt->write_using_libxml2)
782 ret = yaz_marc_write_xml(mt, &root_ptr, ns, format, type);
784 ret = yaz_marc_write_xml_turbo_xml(mt, &root_ptr, ns, format, type);
788 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
791 xmlDocSetRootElement(doc, root_ptr);
792 xmlDocDumpMemory(doc, &buf_out, &len_out);
794 wrbuf_write(wr, (const char *) buf_out, len_out);
805 return yaz_marc_write_marcxml_wrbuf(mt, wr, ns, format, type, turbo);
808 int yaz_marc_write_marcxml(yaz_marc_t mt, WRBUF wr)
810 /* set leader 09 to 'a' for UNICODE */
811 /* http://www.loc.gov/marc/bibliographic/ecbdldrd.html#mrcblea */
812 if (!mt->leader_spec)
813 yaz_marc_modify_leader(mt, 9, "a");
814 return yaz_marc_write_marcxml_ns(mt, wr,
815 "http://www.loc.gov/MARC21/slim",
819 int yaz_marc_write_turbo_xml(yaz_marc_t mt, WRBUF wr)
821 /* set leader 09 to 'a' for UNICODE */
822 /* http://www.loc.gov/marc/bibliographic/ecbdldrd.html#mrcblea */
823 if (!mt->leader_spec)
824 yaz_marc_modify_leader(mt, 9, "a");
825 return yaz_marc_write_marcxml_ns(mt, wr,
826 "http://www.indexdata.com/MARC21/turboxml", 0, 0, 1);
829 int yaz_marc_write_marcxchange(yaz_marc_t mt, WRBUF wr,
833 return yaz_marc_write_marcxml_ns(mt, wr,
834 "info:lc/xmlns/marcxchange-v1",
840 void add_marc_datafield_turbo_xml(yaz_marc_t mt, struct yaz_marc_node *n,
842 xmlNsPtr ns_record, WRBUF wr_cdata,
843 int identifier_length)
846 struct yaz_marc_subfield *s;
847 WRBUF subfield_name = wrbuf_alloc();
849 //TODO consider if safe
852 strncpy(field + 1, n->u.datafield.tag, 3);
854 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST field, 0);
856 if (n->u.datafield.indicator)
859 for (i = 0; n->u.datafield.indicator[i]; i++)
864 ind_val[0] = n->u.datafield.indicator[i];
866 sprintf(ind_str, "%s%d", indicator_name[1], i+1);
867 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
870 for (s = n->u.datafield.subfields; s; s = s->next)
873 xmlNode *ptr_subfield;
874 size_t using_code_len = get_subfield_len(mt, s->code_data,
876 wrbuf_rewind(wr_cdata);
877 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, s->code_data + using_code_len);
878 marc_iconv_reset(mt, wr_cdata);
880 wrbuf_rewind(subfield_name);
881 wrbuf_puts(subfield_name, "s");
882 not_written = element_name_append_attribute_value(mt, subfield_name, 0, s->code_data, using_code_len) != 0;
883 ptr_subfield = xmlNewTextChild(ptr, ns_record,
884 BAD_CAST wrbuf_cstr(subfield_name),
885 BAD_CAST wrbuf_cstr(wr_cdata));
888 // Generate code attribute value and add
889 wrbuf_rewind(wr_cdata);
890 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,s->code_data, using_code_len);
891 xmlNewProp(ptr_subfield, BAD_CAST "code", BAD_CAST wrbuf_cstr(wr_cdata));
894 wrbuf_destroy(subfield_name);
897 static int yaz_marc_write_xml_turbo_xml(yaz_marc_t mt, xmlNode **root_ptr,
902 struct yaz_marc_node *n;
903 int identifier_length;
904 const char *leader = 0;
909 for (n = mt->nodes; n; n = n->next)
910 if (n->which == YAZ_MARC_LEADER)
912 leader = n->u.leader;
918 if (!atoi_n_check(leader+11, 1, &identifier_length))
921 wr_cdata = wrbuf_alloc();
923 record_ptr = xmlNewNode(0, BAD_CAST "r");
924 *root_ptr = record_ptr;
926 ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
927 xmlSetNs(record_ptr, ns_record);
930 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
932 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
933 for (n = mt->nodes; n; n = n->next)
943 case YAZ_MARC_DATAFIELD:
944 add_marc_datafield_turbo_xml(mt, n, record_ptr, ns_record, wr_cdata, identifier_length);
946 case YAZ_MARC_CONTROLFIELD:
947 wrbuf_rewind(wr_cdata);
948 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
949 marc_iconv_reset(mt, wr_cdata);
951 strncpy(field + 1, n->u.controlfield.tag, 3);
952 ptr = xmlNewTextChild(record_ptr, ns_record,
954 BAD_CAST wrbuf_cstr(wr_cdata));
956 case YAZ_MARC_COMMENT:
957 ptr = xmlNewComment(BAD_CAST n->u.comment);
958 xmlAddChild(record_ptr, ptr);
960 case YAZ_MARC_LEADER:
962 char *field = "leader";
964 xmlNewTextChild(record_ptr, ns_record, BAD_CAST field,
965 BAD_CAST n->u.leader);
970 wrbuf_destroy(wr_cdata);
975 int yaz_marc_write_xml(yaz_marc_t mt, xmlNode **root_ptr,
980 struct yaz_marc_node *n;
981 int identifier_length;
982 const char *leader = 0;
987 for (n = mt->nodes; n; n = n->next)
988 if (n->which == YAZ_MARC_LEADER)
990 leader = n->u.leader;
996 if (!atoi_n_check(leader+11, 1, &identifier_length))
999 wr_cdata = wrbuf_alloc();
1001 record_ptr = xmlNewNode(0, BAD_CAST "record");
1002 *root_ptr = record_ptr;
1004 ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
1005 xmlSetNs(record_ptr, ns_record);
1008 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
1010 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
1011 for (n = mt->nodes; n; n = n->next)
1013 struct yaz_marc_subfield *s;
1018 case YAZ_MARC_DATAFIELD:
1019 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
1020 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
1021 if (n->u.datafield.indicator)
1024 for (i = 0; n->u.datafield.indicator[i]; i++)
1029 sprintf(ind_str, "ind%d", i+1);
1030 ind_val[0] = n->u.datafield.indicator[i];
1032 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
1035 for (s = n->u.datafield.subfields; s; s = s->next)
1037 xmlNode *ptr_subfield;
1038 size_t using_code_len = get_subfield_len(mt, s->code_data,
1040 wrbuf_rewind(wr_cdata);
1041 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd,
1042 s->code_data + using_code_len);
1043 marc_iconv_reset(mt, wr_cdata);
1044 ptr_subfield = xmlNewTextChild(
1046 BAD_CAST "subfield", BAD_CAST wrbuf_cstr(wr_cdata));
1048 wrbuf_rewind(wr_cdata);
1049 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,
1050 s->code_data, using_code_len);
1051 xmlNewProp(ptr_subfield, BAD_CAST "code",
1052 BAD_CAST wrbuf_cstr(wr_cdata));
1055 case YAZ_MARC_CONTROLFIELD:
1056 wrbuf_rewind(wr_cdata);
1057 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
1058 marc_iconv_reset(mt, wr_cdata);
1060 ptr = xmlNewTextChild(record_ptr, ns_record,
1061 BAD_CAST "controlfield",
1062 BAD_CAST wrbuf_cstr(wr_cdata));
1064 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
1066 case YAZ_MARC_COMMENT:
1067 ptr = xmlNewComment(BAD_CAST n->u.comment);
1068 xmlAddChild(record_ptr, ptr);
1070 case YAZ_MARC_LEADER:
1071 xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
1072 BAD_CAST n->u.leader);
1076 wrbuf_destroy(wr_cdata);
1082 int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
1084 struct yaz_marc_node *n;
1085 int indicator_length;
1086 int identifier_length;
1087 int length_data_entry;
1088 int length_starting;
1089 int length_implementation;
1090 int data_offset = 0;
1091 const char *leader = 0;
1092 WRBUF wr_dir, wr_head, wr_data_tmp;
1095 for (n = mt->nodes; n; n = n->next)
1096 if (n->which == YAZ_MARC_LEADER)
1097 leader = n->u.leader;
1101 if (!atoi_n_check(leader+10, 1, &indicator_length))
1103 if (!atoi_n_check(leader+11, 1, &identifier_length))
1105 if (!atoi_n_check(leader+20, 1, &length_data_entry))
1107 if (!atoi_n_check(leader+21, 1, &length_starting))
1109 if (!atoi_n_check(leader+22, 1, &length_implementation))
1112 wr_data_tmp = wrbuf_alloc();
1113 wr_dir = wrbuf_alloc();
1114 for (n = mt->nodes; n; n = n->next)
1116 int data_length = 0;
1117 struct yaz_marc_subfield *s;
1121 case YAZ_MARC_DATAFIELD:
1122 wrbuf_printf(wr_dir, "%.3s", n->u.datafield.tag);
1123 data_length += indicator_length;
1124 wrbuf_rewind(wr_data_tmp);
1125 for (s = n->u.datafield.subfields; s; s = s->next)
1127 /* write dummy IDFS + content */
1128 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
1129 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
1130 marc_iconv_reset(mt, wr_data_tmp);
1132 /* write dummy FS (makes MARC-8 to become ASCII) */
1133 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
1134 marc_iconv_reset(mt, wr_data_tmp);
1135 data_length += wrbuf_len(wr_data_tmp);
1137 case YAZ_MARC_CONTROLFIELD:
1138 wrbuf_printf(wr_dir, "%.3s", n->u.controlfield.tag);
1140 wrbuf_rewind(wr_data_tmp);
1141 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd,
1142 n->u.controlfield.data);
1143 marc_iconv_reset(mt, wr_data_tmp);
1144 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
1145 marc_iconv_reset(mt, wr_data_tmp);
1146 data_length += wrbuf_len(wr_data_tmp);
1148 case YAZ_MARC_COMMENT:
1150 case YAZ_MARC_LEADER:
1155 wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
1156 wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
1157 data_offset += data_length;
1160 /* mark end of directory */
1161 wrbuf_putc(wr_dir, ISO2709_FS);
1163 /* base address of data (comes after leader+directory) */
1164 base_address = 24 + wrbuf_len(wr_dir);
1166 wr_head = wrbuf_alloc();
1168 /* write record length */
1169 wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
1170 /* from "original" leader */
1171 wrbuf_write(wr_head, leader+5, 7);
1172 /* base address of data */
1173 wrbuf_printf(wr_head, "%05d", base_address);
1174 /* from "original" leader */
1175 wrbuf_write(wr_head, leader+17, 7);
1177 wrbuf_write(wr, wrbuf_buf(wr_head), 24);
1178 wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
1179 wrbuf_destroy(wr_head);
1180 wrbuf_destroy(wr_dir);
1181 wrbuf_destroy(wr_data_tmp);
1183 for (n = mt->nodes; n; n = n->next)
1185 struct yaz_marc_subfield *s;
1189 case YAZ_MARC_DATAFIELD:
1190 wrbuf_printf(wr, "%.*s", indicator_length,
1191 n->u.datafield.indicator);
1192 for (s = n->u.datafield.subfields; s; s = s->next)
1194 wrbuf_putc(wr, ISO2709_IDFS);
1195 wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
1196 marc_iconv_reset(mt, wr);
1198 wrbuf_putc(wr, ISO2709_FS);
1200 case YAZ_MARC_CONTROLFIELD:
1201 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
1202 marc_iconv_reset(mt, wr);
1203 wrbuf_putc(wr, ISO2709_FS);
1205 case YAZ_MARC_COMMENT:
1207 case YAZ_MARC_LEADER:
1211 wrbuf_printf(wr, "%c", ISO2709_RS);
1216 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
1218 int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
1221 s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
1223 return -1; /* error */
1224 return r; /* OK, return length > 0 */
1227 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
1228 const char **result, size_t *rsize)
1232 wrbuf_rewind(mt->m_wr);
1233 r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
1235 *result = wrbuf_cstr(mt->m_wr);
1237 *rsize = wrbuf_len(mt->m_wr);
1241 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
1243 mt->output_format = xmlmode;
1246 void yaz_marc_debug(yaz_marc_t mt, int level)
1252 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
1257 yaz_iconv_t yaz_marc_get_iconv(yaz_marc_t mt)
1259 return mt->iconv_cd;
1262 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
1264 struct yaz_marc_node *n;
1266 for (n = mt->nodes; n; n = n->next)
1267 if (n->which == YAZ_MARC_LEADER)
1269 leader = n->u.leader;
1270 memcpy(leader+off, str, strlen(str));
1275 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
1277 xfree(mt->leader_spec);
1278 mt->leader_spec = 0;
1281 char dummy_leader[24];
1282 if (marc_exec_leader(leader_spec, dummy_leader, 24))
1284 mt->leader_spec = xstrdup(leader_spec);
1289 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
1291 const char *cp = leader_spec;
1296 int no_read = 0, no = 0;
1298 no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1299 if (no < 2 || no_read < 3)
1301 if (pos < 0 || (size_t) pos >= size)
1306 const char *vp = strchr(val+1, '\'');
1312 if (len + pos > size)
1314 memcpy(leader + pos, val+1, len);
1316 else if (*val >= '0' && *val <= '9')
1332 int yaz_marc_decode_formatstr(const char *arg)
1335 if (!strcmp(arg, "marc"))
1336 mode = YAZ_MARC_ISO2709;
1337 if (!strcmp(arg, "marcxml"))
1338 mode = YAZ_MARC_MARCXML;
1339 if (!strcmp(arg, "tmarcxml"))
1340 mode = YAZ_MARC_TMARCXML;
1341 if (!strcmp(arg, "marcxchange"))
1342 mode = YAZ_MARC_XCHANGE;
1343 if (!strcmp(arg, "line"))
1344 mode = YAZ_MARC_LINE;
1348 void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
1350 mt->write_using_libxml2 = enable;
1356 * c-file-style: "Stroustrup"
1357 * indent-tabs-mode: nil
1359 * vim: shiftwidth=4 tabstop=8 expandtab