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 /** \brief adds a attribute value to the element name if it is plain chars
250 If not, and if the attribute name is not null, it will append a
251 attribute element with the value if attribute name is null it will
252 return a non-zero value meaning it couldnt handle the value.
254 static int element_name_append_attribute_value(
255 yaz_marc_t mt, WRBUF buffer,
256 const char *attribute_name, char *code_data, size_t code_len)
258 /* TODO Map special codes to something possible for XML ELEMENT names */
263 for (index = 0; index < code_len; index++)
265 if (!((code_data[index] >= '0' && code_data[index] <= '9') ||
266 (code_data[index] >= 'a' && code_data[index] <= 'z') ||
267 (code_data[index] >= 'A' && code_data[index] <= 'Z')))
270 /* Add as attribute */
271 if (encode && attribute_name)
272 wrbuf_printf(buffer, " %s=\"", attribute_name);
274 if (!encode || attribute_name)
275 wrbuf_iconv_write_cdata(buffer, mt->iconv_cd, code_data, code_len);
279 if (encode && attribute_name)
280 wrbuf_printf(buffer, "\""); /* return error if we couldn't handle it.*/
285 void yaz_marc_add_datafield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
286 const char *indicator, size_t indicator_len)
288 struct yaz_marc_node *n = yaz_marc_add_node(mt);
289 n->which = YAZ_MARC_DATAFIELD;
290 n->u.datafield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
291 n->u.datafield.indicator =
292 nmem_strdupn(mt->nmem, indicator, indicator_len);
293 n->u.datafield.subfields = 0;
295 /* make subfield_pp the current (last one) */
296 mt->subfield_pp = &n->u.datafield.subfields;
299 void yaz_marc_add_datafield_xml2(yaz_marc_t mt, char *tag_value, char *indicators)
301 struct yaz_marc_node *n = yaz_marc_add_node(mt);
302 n->which = YAZ_MARC_DATAFIELD;
303 n->u.datafield.tag = tag_value;
304 n->u.datafield.indicator = indicators;
305 n->u.datafield.subfields = 0;
307 /* make subfield_pp the current (last one) */
308 mt->subfield_pp = &n->u.datafield.subfields;
311 void yaz_marc_datafield_set_indicators(struct yaz_marc_node *n, char *indicator)
313 n->u.datafield.indicator = indicator;
318 void yaz_marc_add_subfield(yaz_marc_t mt,
319 const char *code_data, size_t code_data_len)
326 sprintf(msg, "subfield:");
327 for (i = 0; i < 16 && i < code_data_len; i++)
328 sprintf(msg + strlen(msg), " %02X", code_data[i] & 0xff);
329 if (i < code_data_len)
330 sprintf(msg + strlen(msg), " ..");
331 yaz_marc_add_comment(mt, msg);
336 struct yaz_marc_subfield *n = (struct yaz_marc_subfield *)
337 nmem_malloc(mt->nmem, sizeof(*n));
338 n->code_data = nmem_strdupn(mt->nmem, code_data, code_data_len);
340 /* mark subfield_pp to point to this one, so we append here next */
341 *mt->subfield_pp = n;
342 mt->subfield_pp = &n->next;
346 void yaz_marc_set_leader(yaz_marc_t mt, const char *leader_c,
347 int *indicator_length,
348 int *identifier_length,
350 int *length_data_entry,
351 int *length_starting,
352 int *length_implementation)
356 memcpy(leader, leader_c, 24);
358 if (!atoi_n_check(leader+10, 1, indicator_length))
361 "Indicator length at offset 10 should hold a digit."
364 *indicator_length = 2;
366 if (!atoi_n_check(leader+11, 1, identifier_length))
369 "Identifier length at offset 11 should hold a digit."
372 *identifier_length = 2;
374 if (!atoi_n_check(leader+12, 5, base_address))
377 "Base address at offsets 12..16 should hold a number."
381 if (!atoi_n_check(leader+20, 1, length_data_entry))
384 "Length data entry at offset 20 should hold a digit."
386 *length_data_entry = 4;
389 if (!atoi_n_check(leader+21, 1, length_starting))
392 "Length starting at offset 21 should hold a digit."
394 *length_starting = 5;
397 if (!atoi_n_check(leader+22, 1, length_implementation))
400 "Length implementation at offset 22 should hold a digit."
402 *length_implementation = 0;
408 yaz_marc_cprintf(mt, "Indicator length %5d", *indicator_length);
409 yaz_marc_cprintf(mt, "Identifier length %5d", *identifier_length);
410 yaz_marc_cprintf(mt, "Base address %5d", *base_address);
411 yaz_marc_cprintf(mt, "Length data entry %5d", *length_data_entry);
412 yaz_marc_cprintf(mt, "Length starting %5d", *length_starting);
413 yaz_marc_cprintf(mt, "Length implementation %5d", *length_implementation);
415 yaz_marc_add_leader(mt, leader, 24);
418 void yaz_marc_subfield_str(yaz_marc_t mt, const char *s)
420 strncpy(mt->subfield_str, s, sizeof(mt->subfield_str)-1);
421 mt->subfield_str[sizeof(mt->subfield_str)-1] = '\0';
424 void yaz_marc_endline_str(yaz_marc_t mt, const char *s)
426 strncpy(mt->endline_str, s, sizeof(mt->endline_str)-1);
427 mt->endline_str[sizeof(mt->endline_str)-1] = '\0';
430 /* try to guess how many bytes the identifier really is! */
431 static size_t cdata_one_character(yaz_marc_t mt, const char *buf)
436 for (i = 1; i<5; i++)
439 size_t outbytesleft = sizeof(outbuf);
441 const char *inp = buf;
443 size_t inbytesleft = i;
444 size_t r = yaz_iconv(mt->iconv_cd, (char**) &inp, &inbytesleft,
445 &outp, &outbytesleft);
446 if (r != (size_t) (-1))
447 return i; /* got a complete sequence */
449 return 1; /* giving up */
451 return 1; /* we don't know */
454 void yaz_marc_reset(yaz_marc_t mt)
456 nmem_reset(mt->nmem);
458 mt->nodes_pp = &mt->nodes;
462 int yaz_marc_write_check(yaz_marc_t mt, WRBUF wr)
464 struct yaz_marc_node *n;
465 int identifier_length;
466 const char *leader = 0;
468 for (n = mt->nodes; n; n = n->next)
469 if (n->which == YAZ_MARC_LEADER)
471 leader = n->u.leader;
477 if (!atoi_n_check(leader+11, 1, &identifier_length))
480 for (n = mt->nodes; n; n = n->next)
484 case YAZ_MARC_COMMENT:
485 wrbuf_iconv_write(wr, mt->iconv_cd,
486 n->u.comment, strlen(n->u.comment));
487 wrbuf_puts(wr, "\n");
496 static size_t get_subfield_len(yaz_marc_t mt, const char *data,
497 int identifier_length)
499 /* if identifier length is 2 (most MARCs) or less (probably an error),
500 the code is a single character .. However we've
501 seen multibyte codes, so see how big it really is */
502 if (identifier_length > 2)
503 return identifier_length - 1;
505 return cdata_one_character(mt, data);
508 int yaz_marc_write_line(yaz_marc_t mt, WRBUF wr)
510 struct yaz_marc_node *n;
511 int identifier_length;
512 const char *leader = 0;
514 for (n = mt->nodes; n; n = n->next)
515 if (n->which == YAZ_MARC_LEADER)
517 leader = n->u.leader;
523 if (!atoi_n_check(leader+11, 1, &identifier_length))
526 for (n = mt->nodes; n; n = n->next)
528 struct yaz_marc_subfield *s;
531 case YAZ_MARC_DATAFIELD:
532 wrbuf_printf(wr, "%s %s", n->u.datafield.tag,
533 n->u.datafield.indicator);
534 for (s = n->u.datafield.subfields; s; s = s->next)
536 size_t using_code_len = get_subfield_len(mt, s->code_data,
539 wrbuf_puts (wr, mt->subfield_str);
540 wrbuf_iconv_write(wr, mt->iconv_cd, s->code_data,
542 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
543 wrbuf_iconv_puts(wr, mt->iconv_cd,
544 s->code_data + using_code_len);
545 marc_iconv_reset(mt, wr);
547 wrbuf_puts (wr, mt->endline_str);
549 case YAZ_MARC_CONTROLFIELD:
550 wrbuf_printf(wr, "%s", n->u.controlfield.tag);
551 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
552 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
553 marc_iconv_reset(mt, wr);
554 wrbuf_puts (wr, mt->endline_str);
556 case YAZ_MARC_COMMENT:
558 wrbuf_iconv_write(wr, mt->iconv_cd,
559 n->u.comment, strlen(n->u.comment));
560 marc_iconv_reset(mt, wr);
561 wrbuf_puts(wr, ")\n");
563 case YAZ_MARC_LEADER:
564 wrbuf_printf(wr, "%s\n", n->u.leader);
567 wrbuf_puts(wr, "\n");
571 int yaz_marc_write_trailer(yaz_marc_t mt, WRBUF wr)
573 if (mt->enable_collection == collection_second)
575 switch(mt->output_format)
577 case YAZ_MARC_MARCXML:
578 case YAZ_MARC_TURBOMARC:
579 wrbuf_printf(wr, "</collection>\n");
581 case YAZ_MARC_XCHANGE:
582 wrbuf_printf(wr, "</collection>\n");
589 void yaz_marc_enable_collection(yaz_marc_t mt)
591 mt->enable_collection = collection_first;
594 int yaz_marc_write_mode(yaz_marc_t mt, WRBUF wr)
596 switch(mt->output_format)
599 return yaz_marc_write_line(mt, wr);
600 case YAZ_MARC_MARCXML:
601 return yaz_marc_write_marcxml(mt, wr);
602 case YAZ_MARC_TURBOMARC:
603 return yaz_marc_write_turbomarc(mt, wr);
604 case YAZ_MARC_XCHANGE:
605 return yaz_marc_write_marcxchange(mt, wr, 0, 0); /* no format, type */
606 case YAZ_MARC_ISO2709:
607 return yaz_marc_write_iso2709(mt, wr);
609 return yaz_marc_write_check(mt, wr);
614 static const char *record_name[2] = { "record", "r"};
615 static const char *leader_name[2] = { "leader", "l"};
616 static const char *controlfield_name[2] = { "controlfield", "c"};
617 static const char *datafield_name[2] = { "datafield", "d"};
618 static const char *indicator_name[2] = { "ind", "i"};
619 static const char *subfield_name[2] = { "subfield", "s"};
621 /** \brief common MARC XML/Xchange/turbomarc writer
623 \param wr WRBUF output
624 \param ns XMLNS for the elements
625 \param format record format (e.g. "MARC21")
626 \param type record type (e.g. "Bibliographic")
627 \param turbo =1 for turbomarc
631 static int yaz_marc_write_marcxml_wrbuf(yaz_marc_t mt, WRBUF wr,
637 struct yaz_marc_node *n;
638 int identifier_length;
639 const char *leader = 0;
641 for (n = mt->nodes; n; n = n->next)
642 if (n->which == YAZ_MARC_LEADER)
644 leader = n->u.leader;
650 if (!atoi_n_check(leader+11, 1, &identifier_length))
653 if (mt->enable_collection != no_collection)
655 if (mt->enable_collection == collection_first)
657 wrbuf_printf(wr, "<collection xmlns=\"%s\">\n", ns);
658 mt->enable_collection = collection_second;
660 wrbuf_printf(wr, "<%s", record_name[turbo]);
664 wrbuf_printf(wr, "<%s xmlns=\"%s\"", record_name[turbo], ns);
667 wrbuf_printf(wr, " format=\"%.80s\"", format);
669 wrbuf_printf(wr, " type=\"%.80s\"", type);
670 wrbuf_printf(wr, ">\n");
671 for (n = mt->nodes; n; n = n->next)
673 struct yaz_marc_subfield *s;
677 case YAZ_MARC_DATAFIELD:
679 wrbuf_printf(wr, " <%s", datafield_name[turbo]);
681 wrbuf_printf(wr, " tag=\"");
682 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
683 strlen(n->u.datafield.tag));
685 wrbuf_printf(wr, "\"");
686 if (n->u.datafield.indicator)
689 for (i = 0; n->u.datafield.indicator[i]; i++)
691 wrbuf_printf(wr, " %s%d=\"", indicator_name[turbo], i+1);
692 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
693 n->u.datafield.indicator+i, 1);
694 wrbuf_iconv_puts(wr, mt->iconv_cd, "\"");
697 wrbuf_printf(wr, ">\n");
698 for (s = n->u.datafield.subfields; s; s = s->next)
700 size_t using_code_len = get_subfield_len(mt, s->code_data,
702 wrbuf_printf(wr, " <%s", subfield_name[turbo]);
705 wrbuf_printf(wr, " code=\"");
706 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
707 s->code_data, using_code_len);
708 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
712 element_name_append_attribute_value(mt, wr, "code", s->code_data, using_code_len);
715 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
716 s->code_data + using_code_len,
717 strlen(s->code_data + using_code_len));
718 marc_iconv_reset(mt, wr);
719 wrbuf_printf(wr, "</%s", subfield_name[turbo]);
721 element_name_append_attribute_value(mt, wr, 0, s->code_data, using_code_len);
722 wrbuf_puts(wr, ">\n");
724 wrbuf_printf(wr, " </%s", datafield_name[turbo]);
727 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
728 strlen(n->u.datafield.tag));
729 wrbuf_printf(wr, ">\n");
731 case YAZ_MARC_CONTROLFIELD:
732 wrbuf_printf(wr, " <%s", controlfield_name[turbo]);
735 wrbuf_printf(wr, " tag=\"");
736 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
737 strlen(n->u.controlfield.tag));
738 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
742 /* TODO convert special */
743 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
744 strlen(n->u.controlfield.tag));
745 wrbuf_iconv_puts(wr, mt->iconv_cd, ">");
747 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
748 n->u.controlfield.data,
749 strlen(n->u.controlfield.data));
750 marc_iconv_reset(mt, wr);
751 wrbuf_printf(wr, "</%s", controlfield_name[turbo]);
752 /* TODO convert special */
754 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
755 strlen(n->u.controlfield.tag));
756 wrbuf_puts(wr, ">\n");
758 case YAZ_MARC_COMMENT:
759 wrbuf_printf(wr, "<!-- ");
760 wrbuf_puts(wr, n->u.comment);
761 wrbuf_printf(wr, " -->\n");
763 case YAZ_MARC_LEADER:
764 wrbuf_printf(wr, " <%s>", leader_name[turbo]);
765 wrbuf_iconv_write_cdata(wr,
766 0 , /* no charset conversion for leader */
767 n->u.leader, strlen(n->u.leader));
768 wrbuf_printf(wr, "</%s>\n", leader_name[turbo]);
771 wrbuf_printf(wr, "</%s>\n", record_name[turbo]);
775 static int yaz_marc_write_marcxml_ns(yaz_marc_t mt, WRBUF wr,
781 if (mt->write_using_libxml2)
788 ret = yaz_marc_write_xml(mt, &root_ptr, ns, format, type);
790 ret = yaz_marc_write_xml_turbo_xml(mt, &root_ptr, ns, format, type);
794 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
797 xmlDocSetRootElement(doc, root_ptr);
798 xmlDocDumpMemory(doc, &buf_out, &len_out);
800 wrbuf_write(wr, (const char *) buf_out, len_out);
811 return yaz_marc_write_marcxml_wrbuf(mt, wr, ns, format, type, turbo);
814 int yaz_marc_write_marcxml(yaz_marc_t mt, WRBUF wr)
816 /* set leader 09 to 'a' for UNICODE */
817 /* http://www.loc.gov/marc/bibliographic/ecbdldrd.html#mrcblea */
818 if (!mt->leader_spec)
819 yaz_marc_modify_leader(mt, 9, "a");
820 return yaz_marc_write_marcxml_ns(mt, wr,
821 "http://www.loc.gov/MARC21/slim",
825 int yaz_marc_write_turbomarc(yaz_marc_t mt, WRBUF wr)
827 /* set leader 09 to 'a' for UNICODE */
828 /* http://www.loc.gov/marc/bibliographic/ecbdldrd.html#mrcblea */
829 if (!mt->leader_spec)
830 yaz_marc_modify_leader(mt, 9, "a");
831 return yaz_marc_write_marcxml_ns(mt, wr,
832 "http://www.indexdata.com/turbomarc", 0, 0, 1);
835 int yaz_marc_write_marcxchange(yaz_marc_t mt, WRBUF wr,
839 return yaz_marc_write_marcxml_ns(mt, wr,
840 "info:lc/xmlns/marcxchange-v1",
846 void add_marc_datafield_turbo_xml(yaz_marc_t mt, struct yaz_marc_node *n,
848 xmlNsPtr ns_record, WRBUF wr_cdata,
849 int identifier_length)
852 struct yaz_marc_subfield *s;
853 WRBUF subfield_name = wrbuf_alloc();
855 /* TODO consider if safe */
858 strncpy(field + 1, n->u.datafield.tag, 3);
860 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST field, 0);
862 if (n->u.datafield.indicator)
865 for (i = 0; n->u.datafield.indicator[i]; i++)
870 ind_val[0] = n->u.datafield.indicator[i];
872 sprintf(ind_str, "%s%d", indicator_name[1], i+1);
873 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
876 for (s = n->u.datafield.subfields; s; s = s->next)
879 xmlNode *ptr_subfield;
880 size_t using_code_len = get_subfield_len(mt, s->code_data,
882 wrbuf_rewind(wr_cdata);
883 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, s->code_data + using_code_len);
884 marc_iconv_reset(mt, wr_cdata);
886 wrbuf_rewind(subfield_name);
887 wrbuf_puts(subfield_name, "s");
888 not_written = element_name_append_attribute_value(mt, subfield_name, 0, s->code_data, using_code_len) != 0;
889 ptr_subfield = xmlNewTextChild(ptr, ns_record,
890 BAD_CAST wrbuf_cstr(subfield_name),
891 BAD_CAST wrbuf_cstr(wr_cdata));
894 /* Generate code attribute value and add */
895 wrbuf_rewind(wr_cdata);
896 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,s->code_data, using_code_len);
897 xmlNewProp(ptr_subfield, BAD_CAST "code", BAD_CAST wrbuf_cstr(wr_cdata));
900 wrbuf_destroy(subfield_name);
903 static int yaz_marc_write_xml_turbo_xml(yaz_marc_t mt, xmlNode **root_ptr,
908 struct yaz_marc_node *n;
909 int identifier_length;
910 const char *leader = 0;
915 for (n = mt->nodes; n; n = n->next)
916 if (n->which == YAZ_MARC_LEADER)
918 leader = n->u.leader;
924 if (!atoi_n_check(leader+11, 1, &identifier_length))
927 wr_cdata = wrbuf_alloc();
929 record_ptr = xmlNewNode(0, BAD_CAST "r");
930 *root_ptr = record_ptr;
932 ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
933 xmlSetNs(record_ptr, ns_record);
936 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
938 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
939 for (n = mt->nodes; n; n = n->next)
949 case YAZ_MARC_DATAFIELD:
950 add_marc_datafield_turbo_xml(mt, n, record_ptr, ns_record, wr_cdata, identifier_length);
952 case YAZ_MARC_CONTROLFIELD:
953 wrbuf_rewind(wr_cdata);
954 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
955 marc_iconv_reset(mt, wr_cdata);
957 strncpy(field + 1, n->u.controlfield.tag, 3);
958 ptr = xmlNewTextChild(record_ptr, ns_record,
960 BAD_CAST wrbuf_cstr(wr_cdata));
962 case YAZ_MARC_COMMENT:
963 ptr = xmlNewComment(BAD_CAST n->u.comment);
964 xmlAddChild(record_ptr, ptr);
966 case YAZ_MARC_LEADER:
968 char *field = "leader";
970 xmlNewTextChild(record_ptr, ns_record, BAD_CAST field,
971 BAD_CAST n->u.leader);
976 wrbuf_destroy(wr_cdata);
981 int yaz_marc_write_xml(yaz_marc_t mt, xmlNode **root_ptr,
986 struct yaz_marc_node *n;
987 int identifier_length;
988 const char *leader = 0;
993 for (n = mt->nodes; n; n = n->next)
994 if (n->which == YAZ_MARC_LEADER)
996 leader = n->u.leader;
1002 if (!atoi_n_check(leader+11, 1, &identifier_length))
1005 wr_cdata = wrbuf_alloc();
1007 record_ptr = xmlNewNode(0, BAD_CAST "record");
1008 *root_ptr = record_ptr;
1010 ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
1011 xmlSetNs(record_ptr, ns_record);
1014 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
1016 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
1017 for (n = mt->nodes; n; n = n->next)
1019 struct yaz_marc_subfield *s;
1024 case YAZ_MARC_DATAFIELD:
1025 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
1026 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
1027 if (n->u.datafield.indicator)
1030 for (i = 0; n->u.datafield.indicator[i]; i++)
1035 sprintf(ind_str, "ind%d", i+1);
1036 ind_val[0] = n->u.datafield.indicator[i];
1038 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
1041 for (s = n->u.datafield.subfields; s; s = s->next)
1043 xmlNode *ptr_subfield;
1044 size_t using_code_len = get_subfield_len(mt, s->code_data,
1046 wrbuf_rewind(wr_cdata);
1047 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd,
1048 s->code_data + using_code_len);
1049 marc_iconv_reset(mt, wr_cdata);
1050 ptr_subfield = xmlNewTextChild(
1052 BAD_CAST "subfield", BAD_CAST wrbuf_cstr(wr_cdata));
1054 wrbuf_rewind(wr_cdata);
1055 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,
1056 s->code_data, using_code_len);
1057 xmlNewProp(ptr_subfield, BAD_CAST "code",
1058 BAD_CAST wrbuf_cstr(wr_cdata));
1061 case YAZ_MARC_CONTROLFIELD:
1062 wrbuf_rewind(wr_cdata);
1063 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
1064 marc_iconv_reset(mt, wr_cdata);
1066 ptr = xmlNewTextChild(record_ptr, ns_record,
1067 BAD_CAST "controlfield",
1068 BAD_CAST wrbuf_cstr(wr_cdata));
1070 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
1072 case YAZ_MARC_COMMENT:
1073 ptr = xmlNewComment(BAD_CAST n->u.comment);
1074 xmlAddChild(record_ptr, ptr);
1076 case YAZ_MARC_LEADER:
1077 xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
1078 BAD_CAST n->u.leader);
1082 wrbuf_destroy(wr_cdata);
1088 int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
1090 struct yaz_marc_node *n;
1091 int indicator_length;
1092 int identifier_length;
1093 int length_data_entry;
1094 int length_starting;
1095 int length_implementation;
1096 int data_offset = 0;
1097 const char *leader = 0;
1098 WRBUF wr_dir, wr_head, wr_data_tmp;
1101 for (n = mt->nodes; n; n = n->next)
1102 if (n->which == YAZ_MARC_LEADER)
1103 leader = n->u.leader;
1107 if (!atoi_n_check(leader+10, 1, &indicator_length))
1109 if (!atoi_n_check(leader+11, 1, &identifier_length))
1111 if (!atoi_n_check(leader+20, 1, &length_data_entry))
1113 if (!atoi_n_check(leader+21, 1, &length_starting))
1115 if (!atoi_n_check(leader+22, 1, &length_implementation))
1118 wr_data_tmp = wrbuf_alloc();
1119 wr_dir = wrbuf_alloc();
1120 for (n = mt->nodes; n; n = n->next)
1122 int data_length = 0;
1123 struct yaz_marc_subfield *s;
1127 case YAZ_MARC_DATAFIELD:
1128 wrbuf_printf(wr_dir, "%.3s", n->u.datafield.tag);
1129 data_length += indicator_length;
1130 wrbuf_rewind(wr_data_tmp);
1131 for (s = n->u.datafield.subfields; s; s = s->next)
1133 /* write dummy IDFS + content */
1134 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
1135 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
1136 marc_iconv_reset(mt, wr_data_tmp);
1138 /* write dummy FS (makes MARC-8 to become ASCII) */
1139 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
1140 marc_iconv_reset(mt, wr_data_tmp);
1141 data_length += wrbuf_len(wr_data_tmp);
1143 case YAZ_MARC_CONTROLFIELD:
1144 wrbuf_printf(wr_dir, "%.3s", n->u.controlfield.tag);
1146 wrbuf_rewind(wr_data_tmp);
1147 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd,
1148 n->u.controlfield.data);
1149 marc_iconv_reset(mt, wr_data_tmp);
1150 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
1151 marc_iconv_reset(mt, wr_data_tmp);
1152 data_length += wrbuf_len(wr_data_tmp);
1154 case YAZ_MARC_COMMENT:
1156 case YAZ_MARC_LEADER:
1161 wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
1162 wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
1163 data_offset += data_length;
1166 /* mark end of directory */
1167 wrbuf_putc(wr_dir, ISO2709_FS);
1169 /* base address of data (comes after leader+directory) */
1170 base_address = 24 + wrbuf_len(wr_dir);
1172 wr_head = wrbuf_alloc();
1174 /* write record length */
1175 wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
1176 /* from "original" leader */
1177 wrbuf_write(wr_head, leader+5, 7);
1178 /* base address of data */
1179 wrbuf_printf(wr_head, "%05d", base_address);
1180 /* from "original" leader */
1181 wrbuf_write(wr_head, leader+17, 7);
1183 wrbuf_write(wr, wrbuf_buf(wr_head), 24);
1184 wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
1185 wrbuf_destroy(wr_head);
1186 wrbuf_destroy(wr_dir);
1187 wrbuf_destroy(wr_data_tmp);
1189 for (n = mt->nodes; n; n = n->next)
1191 struct yaz_marc_subfield *s;
1195 case YAZ_MARC_DATAFIELD:
1196 wrbuf_printf(wr, "%.*s", indicator_length,
1197 n->u.datafield.indicator);
1198 for (s = n->u.datafield.subfields; s; s = s->next)
1200 wrbuf_putc(wr, ISO2709_IDFS);
1201 wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
1202 marc_iconv_reset(mt, wr);
1204 wrbuf_putc(wr, ISO2709_FS);
1206 case YAZ_MARC_CONTROLFIELD:
1207 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
1208 marc_iconv_reset(mt, wr);
1209 wrbuf_putc(wr, ISO2709_FS);
1211 case YAZ_MARC_COMMENT:
1213 case YAZ_MARC_LEADER:
1217 wrbuf_printf(wr, "%c", ISO2709_RS);
1222 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
1224 int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
1227 s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
1229 return -1; /* error */
1230 return r; /* OK, return length > 0 */
1233 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
1234 const char **result, size_t *rsize)
1238 wrbuf_rewind(mt->m_wr);
1239 r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
1241 *result = wrbuf_cstr(mt->m_wr);
1243 *rsize = wrbuf_len(mt->m_wr);
1247 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
1249 mt->output_format = xmlmode;
1252 void yaz_marc_debug(yaz_marc_t mt, int level)
1258 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
1263 yaz_iconv_t yaz_marc_get_iconv(yaz_marc_t mt)
1265 return mt->iconv_cd;
1268 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
1270 struct yaz_marc_node *n;
1272 for (n = mt->nodes; n; n = n->next)
1273 if (n->which == YAZ_MARC_LEADER)
1275 leader = n->u.leader;
1276 memcpy(leader+off, str, strlen(str));
1281 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
1283 xfree(mt->leader_spec);
1284 mt->leader_spec = 0;
1287 char dummy_leader[24];
1288 if (marc_exec_leader(leader_spec, dummy_leader, 24))
1290 mt->leader_spec = xstrdup(leader_spec);
1295 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
1297 const char *cp = leader_spec;
1302 int no_read = 0, no = 0;
1304 no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1305 if (no < 2 || no_read < 3)
1307 if (pos < 0 || (size_t) pos >= size)
1312 const char *vp = strchr(val+1, '\'');
1318 if (len + pos > size)
1320 memcpy(leader + pos, val+1, len);
1322 else if (*val >= '0' && *val <= '9')
1338 int yaz_marc_decode_formatstr(const char *arg)
1341 if (!strcmp(arg, "marc"))
1342 mode = YAZ_MARC_ISO2709;
1343 if (!strcmp(arg, "marcxml"))
1344 mode = YAZ_MARC_MARCXML;
1345 if (!strcmp(arg, "turbomarc"))
1346 mode = YAZ_MARC_TURBOMARC;
1347 if (!strcmp(arg, "marcxchange"))
1348 mode = YAZ_MARC_XCHANGE;
1349 if (!strcmp(arg, "line"))
1350 mode = YAZ_MARC_LINE;
1354 void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
1356 mt->write_using_libxml2 = enable;
1362 * c-file-style: "Stroustrup"
1363 * indent-tabs-mode: nil
1365 * vim: shiftwidth=4 tabstop=8 expandtab