1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2011 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,
144 static int yaz_marc_write_xml_turbo_xml(yaz_marc_t mt, xmlNode **root_ptr,
150 static struct yaz_marc_node *yaz_marc_add_node(yaz_marc_t mt)
152 struct yaz_marc_node *n = (struct yaz_marc_node *)
153 nmem_malloc(mt->nmem, sizeof(*n));
156 mt->nodes_pp = &n->next;
161 void yaz_marc_add_controlfield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
162 const xmlNode *ptr_data)
164 struct yaz_marc_node *n = yaz_marc_add_node(mt);
165 n->which = YAZ_MARC_CONTROLFIELD;
166 n->u.controlfield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
167 n->u.controlfield.data = nmem_text_node_cdata(ptr_data, mt->nmem);
170 void yaz_marc_add_controlfield_xml2(yaz_marc_t mt, char *tag,
171 const xmlNode *ptr_data)
173 struct yaz_marc_node *n = yaz_marc_add_node(mt);
174 n->which = YAZ_MARC_CONTROLFIELD;
175 n->u.controlfield.tag = tag;
176 n->u.controlfield.data = nmem_text_node_cdata(ptr_data, mt->nmem);
182 void yaz_marc_add_comment(yaz_marc_t mt, char *comment)
184 struct yaz_marc_node *n = yaz_marc_add_node(mt);
185 n->which = YAZ_MARC_COMMENT;
186 n->u.comment = nmem_strdup(mt->nmem, comment);
189 void yaz_marc_cprintf(yaz_marc_t mt, const char *fmt, ...)
195 yaz_vsnprintf(buf, sizeof(buf)-1, fmt, ap);
196 yaz_marc_add_comment(mt, buf);
200 int yaz_marc_get_debug(yaz_marc_t mt)
205 void yaz_marc_add_leader(yaz_marc_t mt, const char *leader, size_t leader_len)
207 struct yaz_marc_node *n = yaz_marc_add_node(mt);
208 n->which = YAZ_MARC_LEADER;
209 n->u.leader = nmem_strdupn(mt->nmem, leader, leader_len);
210 marc_exec_leader(mt->leader_spec, n->u.leader, leader_len);
213 void yaz_marc_add_controlfield(yaz_marc_t mt, const char *tag,
214 const char *data, size_t data_len)
216 struct yaz_marc_node *n = yaz_marc_add_node(mt);
217 n->which = YAZ_MARC_CONTROLFIELD;
218 n->u.controlfield.tag = nmem_strdup(mt->nmem, tag);
219 n->u.controlfield.data = nmem_strdupn(mt->nmem, data, data_len);
225 sprintf(msg, "controlfield:");
226 for (i = 0; i < 16 && i < data_len; i++)
227 sprintf(msg + strlen(msg), " %02X", data[i] & 0xff);
229 sprintf(msg + strlen(msg), " ..");
230 yaz_marc_add_comment(mt, msg);
234 void yaz_marc_add_datafield(yaz_marc_t mt, const char *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_strdup(mt->nmem, tag);
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;
248 // Magic function: adds a attribute value to the element name if it is plain characters.
249 // if not, and if the attribute name is not null, it will append a attribute element with the value
250 // if attribute name is null it will return a non-zero value meaning it couldnt handle the value.
252 static int element_name_append_attribute_value(
253 yaz_marc_t mt, WRBUF buffer,
254 const char *attribute_name, char *code_data, size_t code_len)
256 // TODO Map special codes to something possible for XML ELEMENT names
261 for (index = 0; index < code_len; index++)
263 if (!((code_data[index] >= '0' && code_data[index] <= '9') ||
264 (code_data[index] >= 'a' && code_data[index] <= 'z') ||
265 (code_data[index] >= 'A' && code_data[index] <= 'Z')))
269 if (encode && attribute_name)
270 wrbuf_printf(buffer, " %s=\"", attribute_name);
272 if (!encode || attribute_name)
273 wrbuf_iconv_write_cdata(buffer, mt->iconv_cd, code_data, code_len);
277 if (encode && attribute_name)
278 wrbuf_printf(buffer, "\""); // return error if we couldn't handle it.
283 void yaz_marc_add_datafield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
284 const char *indicator, size_t indicator_len)
286 struct yaz_marc_node *n = yaz_marc_add_node(mt);
287 n->which = YAZ_MARC_DATAFIELD;
288 n->u.datafield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
289 n->u.datafield.indicator =
290 nmem_strdupn(mt->nmem, indicator, indicator_len);
291 n->u.datafield.subfields = 0;
293 /* make subfield_pp the current (last one) */
294 mt->subfield_pp = &n->u.datafield.subfields;
297 void yaz_marc_add_datafield_xml2(yaz_marc_t mt, char *tag_value, char *indicators)
299 struct yaz_marc_node *n = yaz_marc_add_node(mt);
300 n->which = YAZ_MARC_DATAFIELD;
301 n->u.datafield.tag = tag_value;
302 n->u.datafield.indicator = indicators;
303 n->u.datafield.subfields = 0;
305 // make subfield_pp the current (last one)
306 mt->subfield_pp = &n->u.datafield.subfields;
309 void yaz_marc_datafield_set_indicators(struct yaz_marc_node *n, char *indicator)
311 n->u.datafield.indicator = indicator;
316 void yaz_marc_add_subfield(yaz_marc_t mt,
317 const char *code_data, size_t code_data_len)
324 sprintf(msg, "subfield:");
325 for (i = 0; i < 16 && i < code_data_len; i++)
326 sprintf(msg + strlen(msg), " %02X", code_data[i] & 0xff);
327 if (i < code_data_len)
328 sprintf(msg + strlen(msg), " ..");
329 yaz_marc_add_comment(mt, msg);
334 struct yaz_marc_subfield *n = (struct yaz_marc_subfield *)
335 nmem_malloc(mt->nmem, sizeof(*n));
336 n->code_data = nmem_strdupn(mt->nmem, code_data, code_data_len);
338 /* mark subfield_pp to point to this one, so we append here next */
339 *mt->subfield_pp = n;
340 mt->subfield_pp = &n->next;
344 void yaz_marc_set_leader(yaz_marc_t mt, const char *leader_c,
345 int *indicator_length,
346 int *identifier_length,
348 int *length_data_entry,
349 int *length_starting,
350 int *length_implementation)
354 memcpy(leader, leader_c, 24);
356 if (!atoi_n_check(leader+10, 1, indicator_length))
359 "Indicator length at offset 10 should hold a digit."
362 *indicator_length = 2;
364 if (!atoi_n_check(leader+11, 1, identifier_length))
367 "Identifier length at offset 11 should hold a digit."
370 *identifier_length = 2;
372 if (!atoi_n_check(leader+12, 5, base_address))
375 "Base address at offsets 12..16 should hold a number."
379 if (!atoi_n_check(leader+20, 1, length_data_entry))
382 "Length data entry at offset 20 should hold a digit."
384 *length_data_entry = 4;
387 if (!atoi_n_check(leader+21, 1, length_starting))
390 "Length starting at offset 21 should hold a digit."
392 *length_starting = 5;
395 if (!atoi_n_check(leader+22, 1, length_implementation))
398 "Length implementation at offset 22 should hold a digit."
400 *length_implementation = 0;
406 yaz_marc_cprintf(mt, "Indicator length %5d", *indicator_length);
407 yaz_marc_cprintf(mt, "Identifier length %5d", *identifier_length);
408 yaz_marc_cprintf(mt, "Base address %5d", *base_address);
409 yaz_marc_cprintf(mt, "Length data entry %5d", *length_data_entry);
410 yaz_marc_cprintf(mt, "Length starting %5d", *length_starting);
411 yaz_marc_cprintf(mt, "Length implementation %5d", *length_implementation);
413 yaz_marc_add_leader(mt, leader, 24);
416 void yaz_marc_subfield_str(yaz_marc_t mt, const char *s)
418 strncpy(mt->subfield_str, s, sizeof(mt->subfield_str)-1);
419 mt->subfield_str[sizeof(mt->subfield_str)-1] = '\0';
422 void yaz_marc_endline_str(yaz_marc_t mt, const char *s)
424 strncpy(mt->endline_str, s, sizeof(mt->endline_str)-1);
425 mt->endline_str[sizeof(mt->endline_str)-1] = '\0';
428 /* try to guess how many bytes the identifier really is! */
429 static size_t cdata_one_character(yaz_marc_t mt, const char *buf)
434 for (i = 1; i<5; i++)
437 size_t outbytesleft = sizeof(outbuf);
439 const char *inp = buf;
441 size_t inbytesleft = i;
442 size_t r = yaz_iconv(mt->iconv_cd, (char**) &inp, &inbytesleft,
443 &outp, &outbytesleft);
444 if (r != (size_t) (-1))
445 return i; /* got a complete sequence */
447 return 1; /* giving up */
449 return 1; /* we don't know */
452 void yaz_marc_reset(yaz_marc_t mt)
454 nmem_reset(mt->nmem);
456 mt->nodes_pp = &mt->nodes;
460 int yaz_marc_write_check(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)
482 case YAZ_MARC_COMMENT:
483 wrbuf_iconv_write(wr, mt->iconv_cd,
484 n->u.comment, strlen(n->u.comment));
485 wrbuf_puts(wr, "\n");
494 static size_t get_subfield_len(yaz_marc_t mt, const char *data,
495 int identifier_length)
497 /* if identifier length is 2 (most MARCs) or less (probably an error),
498 the code is a single character .. However we've
499 seen multibyte codes, so see how big it really is */
500 if (identifier_length > 2)
501 return identifier_length - 1;
503 return cdata_one_character(mt, data);
506 int yaz_marc_write_line(yaz_marc_t mt, WRBUF wr)
508 struct yaz_marc_node *n;
509 int identifier_length;
510 const char *leader = 0;
512 for (n = mt->nodes; n; n = n->next)
513 if (n->which == YAZ_MARC_LEADER)
515 leader = n->u.leader;
521 if (!atoi_n_check(leader+11, 1, &identifier_length))
524 for (n = mt->nodes; n; n = n->next)
526 struct yaz_marc_subfield *s;
529 case YAZ_MARC_DATAFIELD:
530 wrbuf_printf(wr, "%s %s", n->u.datafield.tag,
531 n->u.datafield.indicator);
532 for (s = n->u.datafield.subfields; s; s = s->next)
534 size_t using_code_len = get_subfield_len(mt, s->code_data,
537 wrbuf_puts (wr, mt->subfield_str);
538 wrbuf_iconv_write(wr, mt->iconv_cd, s->code_data,
540 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
541 wrbuf_iconv_puts(wr, mt->iconv_cd,
542 s->code_data + using_code_len);
543 marc_iconv_reset(mt, wr);
545 wrbuf_puts (wr, mt->endline_str);
547 case YAZ_MARC_CONTROLFIELD:
548 wrbuf_printf(wr, "%s", n->u.controlfield.tag);
549 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
550 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
551 marc_iconv_reset(mt, wr);
552 wrbuf_puts (wr, mt->endline_str);
554 case YAZ_MARC_COMMENT:
556 wrbuf_iconv_write(wr, mt->iconv_cd,
557 n->u.comment, strlen(n->u.comment));
558 marc_iconv_reset(mt, wr);
559 wrbuf_puts(wr, ")\n");
561 case YAZ_MARC_LEADER:
562 wrbuf_printf(wr, "%s\n", n->u.leader);
565 wrbuf_puts(wr, "\n");
569 int yaz_marc_write_trailer(yaz_marc_t mt, WRBUF wr)
571 if (mt->enable_collection == collection_second)
573 switch(mt->output_format)
575 case YAZ_MARC_MARCXML:
576 case YAZ_MARC_TURBOMARC:
577 wrbuf_printf(wr, "</collection>\n");
579 case YAZ_MARC_XCHANGE:
580 wrbuf_printf(wr, "</collection>\n");
587 void yaz_marc_enable_collection(yaz_marc_t mt)
589 mt->enable_collection = collection_first;
592 int yaz_marc_write_mode(yaz_marc_t mt, WRBUF wr)
594 switch(mt->output_format)
597 return yaz_marc_write_line(mt, wr);
598 case YAZ_MARC_MARCXML:
599 return yaz_marc_write_marcxml(mt, wr);
600 case YAZ_MARC_TURBOMARC:
601 return yaz_marc_write_turbomarc(mt, wr);
602 case YAZ_MARC_XCHANGE:
603 return yaz_marc_write_marcxchange(mt, wr, 0, 0); /* no format, type */
604 case YAZ_MARC_ISO2709:
605 return yaz_marc_write_iso2709(mt, wr);
607 return yaz_marc_write_check(mt, wr);
612 static const char *record_name[2] = { "record", "r"};
613 static const char *leader_name[2] = { "leader", "l"};
614 static const char *controlfield_name[2] = { "controlfield", "c"};
615 static const char *datafield_name[2] = { "datafield", "d"};
616 static const char *indicator_name[2] = { "ind", "i"};
617 static const char *subfield_name[2] = { "subfield", "s"};
619 /** \brief common MARC XML/Xchange/turbomarc writer
621 \param wr WRBUF output
622 \param ns XMLNS for the elements
623 \param format record format (e.g. "MARC21")
624 \param type record type (e.g. "Bibliographic")
625 \param turbo =1 for turbomarc
629 static int yaz_marc_write_marcxml_wrbuf(yaz_marc_t mt, WRBUF wr,
635 struct yaz_marc_node *n;
636 int identifier_length;
637 const char *leader = 0;
639 for (n = mt->nodes; n; n = n->next)
640 if (n->which == YAZ_MARC_LEADER)
642 leader = n->u.leader;
648 if (!atoi_n_check(leader+11, 1, &identifier_length))
651 if (mt->enable_collection != no_collection)
653 if (mt->enable_collection == collection_first)
655 wrbuf_printf(wr, "<collection xmlns=\"%s\">\n", ns);
656 mt->enable_collection = collection_second;
658 wrbuf_printf(wr, "<%s", record_name[turbo]);
662 wrbuf_printf(wr, "<%s xmlns=\"%s\"", record_name[turbo], ns);
665 wrbuf_printf(wr, " format=\"%.80s\"", format);
667 wrbuf_printf(wr, " type=\"%.80s\"", type);
668 wrbuf_printf(wr, ">\n");
669 for (n = mt->nodes; n; n = n->next)
671 struct yaz_marc_subfield *s;
675 case YAZ_MARC_DATAFIELD:
677 wrbuf_printf(wr, " <%s", datafield_name[turbo]);
679 wrbuf_printf(wr, " tag=\"");
680 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
681 strlen(n->u.datafield.tag));
683 wrbuf_printf(wr, "\"");
684 if (n->u.datafield.indicator)
687 for (i = 0; n->u.datafield.indicator[i]; i++)
689 wrbuf_printf(wr, " %s%d=\"", indicator_name[turbo], i+1);
690 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
691 n->u.datafield.indicator+i, 1);
692 wrbuf_iconv_puts(wr, mt->iconv_cd, "\"");
695 wrbuf_printf(wr, ">\n");
696 for (s = n->u.datafield.subfields; s; s = s->next)
698 size_t using_code_len = get_subfield_len(mt, s->code_data,
700 wrbuf_printf(wr, " <%s", subfield_name[turbo]);
703 wrbuf_printf(wr, " code=\"");
704 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
705 s->code_data, using_code_len);
706 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
710 element_name_append_attribute_value(mt, wr, "code", s->code_data, using_code_len);
713 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
714 s->code_data + using_code_len,
715 strlen(s->code_data + using_code_len));
716 marc_iconv_reset(mt, wr);
717 wrbuf_printf(wr, "</%s", subfield_name[turbo]);
719 element_name_append_attribute_value(mt, wr, 0, s->code_data, using_code_len);
720 wrbuf_puts(wr, ">\n");
722 wrbuf_printf(wr, " </%s", datafield_name[turbo]);
725 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
726 strlen(n->u.datafield.tag));
727 wrbuf_printf(wr, ">\n");
729 case YAZ_MARC_CONTROLFIELD:
730 wrbuf_printf(wr, " <%s", controlfield_name[turbo]);
733 wrbuf_printf(wr, " tag=\"");
734 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
735 strlen(n->u.controlfield.tag));
736 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
740 //TODO convert special
741 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
742 strlen(n->u.controlfield.tag));
743 wrbuf_iconv_puts(wr, mt->iconv_cd, ">");
745 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
746 n->u.controlfield.data,
747 strlen(n->u.controlfield.data));
748 marc_iconv_reset(mt, wr);
749 wrbuf_printf(wr, "</%s", controlfield_name[turbo]);
750 //TODO convert special
752 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
753 strlen(n->u.controlfield.tag));
754 wrbuf_puts(wr, ">\n");
756 case YAZ_MARC_COMMENT:
757 wrbuf_printf(wr, "<!-- ");
758 wrbuf_puts(wr, n->u.comment);
759 wrbuf_printf(wr, " -->\n");
761 case YAZ_MARC_LEADER:
762 wrbuf_printf(wr, " <%s>", leader_name[turbo]);
763 wrbuf_iconv_write_cdata(wr,
764 0 , /* no charset conversion for leader */
765 n->u.leader, strlen(n->u.leader));
766 wrbuf_printf(wr, "</%s>\n", leader_name[turbo]);
769 wrbuf_printf(wr, "</%s>\n", record_name[turbo]);
773 static int yaz_marc_write_marcxml_ns(yaz_marc_t mt, WRBUF wr,
779 if (mt->write_using_libxml2)
786 ret = yaz_marc_write_xml(mt, &root_ptr, ns, format, type);
788 ret = yaz_marc_write_xml_turbo_xml(mt, &root_ptr, ns, format, type);
792 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
795 xmlDocSetRootElement(doc, root_ptr);
796 xmlDocDumpMemory(doc, &buf_out, &len_out);
798 wrbuf_write(wr, (const char *) buf_out, len_out);
809 return yaz_marc_write_marcxml_wrbuf(mt, wr, ns, format, type, turbo);
812 int yaz_marc_write_marcxml(yaz_marc_t mt, WRBUF wr)
814 /* set leader 09 to 'a' for UNICODE */
815 /* http://www.loc.gov/marc/bibliographic/ecbdldrd.html#mrcblea */
816 if (!mt->leader_spec)
817 yaz_marc_modify_leader(mt, 9, "a");
818 return yaz_marc_write_marcxml_ns(mt, wr,
819 "http://www.loc.gov/MARC21/slim",
823 int yaz_marc_write_turbomarc(yaz_marc_t mt, WRBUF wr)
825 /* set leader 09 to 'a' for UNICODE */
826 /* http://www.loc.gov/marc/bibliographic/ecbdldrd.html#mrcblea */
827 if (!mt->leader_spec)
828 yaz_marc_modify_leader(mt, 9, "a");
829 return yaz_marc_write_marcxml_ns(mt, wr,
830 "http://www.indexdata.com/turbomarc", 0, 0, 1);
833 int yaz_marc_write_marcxchange(yaz_marc_t mt, WRBUF wr,
837 return yaz_marc_write_marcxml_ns(mt, wr,
838 "info:lc/xmlns/marcxchange-v1",
844 void add_marc_datafield_turbo_xml(yaz_marc_t mt, struct yaz_marc_node *n,
846 xmlNsPtr ns_record, WRBUF wr_cdata,
847 int identifier_length)
850 struct yaz_marc_subfield *s;
851 WRBUF subfield_name = wrbuf_alloc();
853 //TODO consider if safe
856 strncpy(field + 1, n->u.datafield.tag, 3);
858 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST field, 0);
860 if (n->u.datafield.indicator)
863 for (i = 0; n->u.datafield.indicator[i]; i++)
868 ind_val[0] = n->u.datafield.indicator[i];
870 sprintf(ind_str, "%s%d", indicator_name[1], i+1);
871 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
874 for (s = n->u.datafield.subfields; s; s = s->next)
877 xmlNode *ptr_subfield;
878 size_t using_code_len = get_subfield_len(mt, s->code_data,
880 wrbuf_rewind(wr_cdata);
881 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, s->code_data + using_code_len);
882 marc_iconv_reset(mt, wr_cdata);
884 wrbuf_rewind(subfield_name);
885 wrbuf_puts(subfield_name, "s");
886 not_written = element_name_append_attribute_value(mt, subfield_name, 0, s->code_data, using_code_len) != 0;
887 ptr_subfield = xmlNewTextChild(ptr, ns_record,
888 BAD_CAST wrbuf_cstr(subfield_name),
889 BAD_CAST wrbuf_cstr(wr_cdata));
892 // Generate code attribute value and add
893 wrbuf_rewind(wr_cdata);
894 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,s->code_data, using_code_len);
895 xmlNewProp(ptr_subfield, BAD_CAST "code", BAD_CAST wrbuf_cstr(wr_cdata));
898 wrbuf_destroy(subfield_name);
901 static int yaz_marc_write_xml_turbo_xml(yaz_marc_t mt, xmlNode **root_ptr,
906 struct yaz_marc_node *n;
907 int identifier_length;
908 const char *leader = 0;
913 for (n = mt->nodes; n; n = n->next)
914 if (n->which == YAZ_MARC_LEADER)
916 leader = n->u.leader;
922 if (!atoi_n_check(leader+11, 1, &identifier_length))
925 wr_cdata = wrbuf_alloc();
927 record_ptr = xmlNewNode(0, BAD_CAST "r");
928 *root_ptr = record_ptr;
930 ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
931 xmlSetNs(record_ptr, ns_record);
934 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
936 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
937 for (n = mt->nodes; n; n = n->next)
947 case YAZ_MARC_DATAFIELD:
948 add_marc_datafield_turbo_xml(mt, n, record_ptr, ns_record, wr_cdata, identifier_length);
950 case YAZ_MARC_CONTROLFIELD:
951 wrbuf_rewind(wr_cdata);
952 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
953 marc_iconv_reset(mt, wr_cdata);
955 strncpy(field + 1, n->u.controlfield.tag, 3);
956 ptr = xmlNewTextChild(record_ptr, ns_record,
958 BAD_CAST wrbuf_cstr(wr_cdata));
960 case YAZ_MARC_COMMENT:
961 ptr = xmlNewComment(BAD_CAST n->u.comment);
962 xmlAddChild(record_ptr, ptr);
964 case YAZ_MARC_LEADER:
966 char *field = "leader";
968 xmlNewTextChild(record_ptr, ns_record, BAD_CAST field,
969 BAD_CAST n->u.leader);
974 wrbuf_destroy(wr_cdata);
979 int yaz_marc_write_xml(yaz_marc_t mt, xmlNode **root_ptr,
984 struct yaz_marc_node *n;
985 int identifier_length;
986 const char *leader = 0;
991 for (n = mt->nodes; n; n = n->next)
992 if (n->which == YAZ_MARC_LEADER)
994 leader = n->u.leader;
1000 if (!atoi_n_check(leader+11, 1, &identifier_length))
1003 wr_cdata = wrbuf_alloc();
1005 record_ptr = xmlNewNode(0, BAD_CAST "record");
1006 *root_ptr = record_ptr;
1008 ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
1009 xmlSetNs(record_ptr, ns_record);
1012 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
1014 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
1015 for (n = mt->nodes; n; n = n->next)
1017 struct yaz_marc_subfield *s;
1022 case YAZ_MARC_DATAFIELD:
1023 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
1024 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
1025 if (n->u.datafield.indicator)
1028 for (i = 0; n->u.datafield.indicator[i]; i++)
1033 sprintf(ind_str, "ind%d", i+1);
1034 ind_val[0] = n->u.datafield.indicator[i];
1036 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
1039 for (s = n->u.datafield.subfields; s; s = s->next)
1041 xmlNode *ptr_subfield;
1042 size_t using_code_len = get_subfield_len(mt, s->code_data,
1044 wrbuf_rewind(wr_cdata);
1045 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd,
1046 s->code_data + using_code_len);
1047 marc_iconv_reset(mt, wr_cdata);
1048 ptr_subfield = xmlNewTextChild(
1050 BAD_CAST "subfield", BAD_CAST wrbuf_cstr(wr_cdata));
1052 wrbuf_rewind(wr_cdata);
1053 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,
1054 s->code_data, using_code_len);
1055 xmlNewProp(ptr_subfield, BAD_CAST "code",
1056 BAD_CAST wrbuf_cstr(wr_cdata));
1059 case YAZ_MARC_CONTROLFIELD:
1060 wrbuf_rewind(wr_cdata);
1061 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
1062 marc_iconv_reset(mt, wr_cdata);
1064 ptr = xmlNewTextChild(record_ptr, ns_record,
1065 BAD_CAST "controlfield",
1066 BAD_CAST wrbuf_cstr(wr_cdata));
1068 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
1070 case YAZ_MARC_COMMENT:
1071 ptr = xmlNewComment(BAD_CAST n->u.comment);
1072 xmlAddChild(record_ptr, ptr);
1074 case YAZ_MARC_LEADER:
1075 xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
1076 BAD_CAST n->u.leader);
1080 wrbuf_destroy(wr_cdata);
1086 int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
1088 struct yaz_marc_node *n;
1089 int indicator_length;
1090 int identifier_length;
1091 int length_data_entry;
1092 int length_starting;
1093 int length_implementation;
1094 int data_offset = 0;
1095 const char *leader = 0;
1096 WRBUF wr_dir, wr_head, wr_data_tmp;
1099 for (n = mt->nodes; n; n = n->next)
1100 if (n->which == YAZ_MARC_LEADER)
1101 leader = n->u.leader;
1105 if (!atoi_n_check(leader+10, 1, &indicator_length))
1107 if (!atoi_n_check(leader+11, 1, &identifier_length))
1109 if (!atoi_n_check(leader+20, 1, &length_data_entry))
1111 if (!atoi_n_check(leader+21, 1, &length_starting))
1113 if (!atoi_n_check(leader+22, 1, &length_implementation))
1116 wr_data_tmp = wrbuf_alloc();
1117 wr_dir = wrbuf_alloc();
1118 for (n = mt->nodes; n; n = n->next)
1120 int data_length = 0;
1121 struct yaz_marc_subfield *s;
1125 case YAZ_MARC_DATAFIELD:
1126 wrbuf_printf(wr_dir, "%.3s", n->u.datafield.tag);
1127 data_length += indicator_length;
1128 wrbuf_rewind(wr_data_tmp);
1129 for (s = n->u.datafield.subfields; s; s = s->next)
1131 /* write dummy IDFS + content */
1132 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
1133 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
1134 marc_iconv_reset(mt, wr_data_tmp);
1136 /* write dummy FS (makes MARC-8 to become ASCII) */
1137 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
1138 marc_iconv_reset(mt, wr_data_tmp);
1139 data_length += wrbuf_len(wr_data_tmp);
1141 case YAZ_MARC_CONTROLFIELD:
1142 wrbuf_printf(wr_dir, "%.3s", n->u.controlfield.tag);
1144 wrbuf_rewind(wr_data_tmp);
1145 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd,
1146 n->u.controlfield.data);
1147 marc_iconv_reset(mt, wr_data_tmp);
1148 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
1149 marc_iconv_reset(mt, wr_data_tmp);
1150 data_length += wrbuf_len(wr_data_tmp);
1152 case YAZ_MARC_COMMENT:
1154 case YAZ_MARC_LEADER:
1159 wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
1160 wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
1161 data_offset += data_length;
1164 /* mark end of directory */
1165 wrbuf_putc(wr_dir, ISO2709_FS);
1167 /* base address of data (comes after leader+directory) */
1168 base_address = 24 + wrbuf_len(wr_dir);
1170 wr_head = wrbuf_alloc();
1172 /* write record length */
1173 wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
1174 /* from "original" leader */
1175 wrbuf_write(wr_head, leader+5, 7);
1176 /* base address of data */
1177 wrbuf_printf(wr_head, "%05d", base_address);
1178 /* from "original" leader */
1179 wrbuf_write(wr_head, leader+17, 7);
1181 wrbuf_write(wr, wrbuf_buf(wr_head), 24);
1182 wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
1183 wrbuf_destroy(wr_head);
1184 wrbuf_destroy(wr_dir);
1185 wrbuf_destroy(wr_data_tmp);
1187 for (n = mt->nodes; n; n = n->next)
1189 struct yaz_marc_subfield *s;
1193 case YAZ_MARC_DATAFIELD:
1194 wrbuf_printf(wr, "%.*s", indicator_length,
1195 n->u.datafield.indicator);
1196 for (s = n->u.datafield.subfields; s; s = s->next)
1198 wrbuf_putc(wr, ISO2709_IDFS);
1199 wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
1200 marc_iconv_reset(mt, wr);
1202 wrbuf_putc(wr, ISO2709_FS);
1204 case YAZ_MARC_CONTROLFIELD:
1205 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
1206 marc_iconv_reset(mt, wr);
1207 wrbuf_putc(wr, ISO2709_FS);
1209 case YAZ_MARC_COMMENT:
1211 case YAZ_MARC_LEADER:
1215 wrbuf_printf(wr, "%c", ISO2709_RS);
1220 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
1222 int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
1225 s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
1227 return -1; /* error */
1228 return r; /* OK, return length > 0 */
1231 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
1232 const char **result, size_t *rsize)
1236 wrbuf_rewind(mt->m_wr);
1237 r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
1239 *result = wrbuf_cstr(mt->m_wr);
1241 *rsize = wrbuf_len(mt->m_wr);
1245 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
1247 mt->output_format = xmlmode;
1250 void yaz_marc_debug(yaz_marc_t mt, int level)
1256 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
1261 yaz_iconv_t yaz_marc_get_iconv(yaz_marc_t mt)
1263 return mt->iconv_cd;
1266 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
1268 struct yaz_marc_node *n;
1270 for (n = mt->nodes; n; n = n->next)
1271 if (n->which == YAZ_MARC_LEADER)
1273 leader = n->u.leader;
1274 memcpy(leader+off, str, strlen(str));
1279 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
1281 xfree(mt->leader_spec);
1282 mt->leader_spec = 0;
1285 char dummy_leader[24];
1286 if (marc_exec_leader(leader_spec, dummy_leader, 24))
1288 mt->leader_spec = xstrdup(leader_spec);
1293 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
1295 const char *cp = leader_spec;
1300 int no_read = 0, no = 0;
1302 no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1303 if (no < 2 || no_read < 3)
1305 if (pos < 0 || (size_t) pos >= size)
1310 const char *vp = strchr(val+1, '\'');
1316 if (len + pos > size)
1318 memcpy(leader + pos, val+1, len);
1320 else if (*val >= '0' && *val <= '9')
1336 int yaz_marc_decode_formatstr(const char *arg)
1339 if (!strcmp(arg, "marc"))
1340 mode = YAZ_MARC_ISO2709;
1341 if (!strcmp(arg, "marcxml"))
1342 mode = YAZ_MARC_MARCXML;
1343 if (!strcmp(arg, "turbomarc"))
1344 mode = YAZ_MARC_TURBOMARC;
1345 if (!strcmp(arg, "marcxchange"))
1346 mode = YAZ_MARC_XCHANGE;
1347 if (!strcmp(arg, "line"))
1348 mode = YAZ_MARC_LINE;
1352 void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
1354 mt->write_using_libxml2 = enable;
1360 * c-file-style: "Stroustrup"
1361 * indent-tabs-mode: nil
1363 * vim: shiftwidth=4 tabstop=8 expandtab