1 /* $Id: recgrs.c,v 1.22 2008-01-09 22:17:34 adam Exp $
2 Copyright (C) 1995-2007
5 This file is part of the Zebra server.
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 #include <sys/types.h>
29 #include <yaz/oid_db.h>
30 #include <yaz/diagbib1.h>
33 #include <idzebra/recgrs.h>
35 #define GRS_MAX_WORD 512
37 struct source_parser {
45 static int sp_lex(struct source_parser *sp)
47 while (*sp->src == ' ')
51 while (*sp->src && !strchr("<>();,-: ", *sp->src))
60 sp->lookahead = *sp->src;
67 static int sp_expr(struct source_parser *sp, data1_node *n, RecWord *wrd);
69 static int sp_range(struct source_parser *sp, data1_node *n, RecWord *wrd)
76 if (sp->lookahead != '(')
78 sp_lex(sp); /* skip ( */
81 if (!sp_expr(sp, n, wrd))
84 if (sp->lookahead != ',')
86 sp_lex(sp); /* skip , */
89 if (!sp_expr(sp, n, &tmp_w))
91 start = atoi_n(tmp_w.term_buf, tmp_w.term_len);
93 if (sp->lookahead == ',')
95 sp_lex(sp); /* skip , */
98 if (!sp_expr(sp, n, &tmp_w))
100 len = atoi_n(tmp_w.term_buf, tmp_w.term_len);
106 if (sp->lookahead != ')')
110 if (wrd->term_buf && wrd->term_len)
112 wrd->term_buf += start;
113 wrd->term_len -= start;
114 if (wrd->term_len > len)
120 static int sp_first(struct source_parser *sp, data1_node *n, RecWord *wrd)
125 if (sp->lookahead != '(')
127 sp_lex(sp); /* skip ( */
128 if (!sp_expr(sp, n, wrd))
130 while (sp->lookahead == ',')
134 sp_lex(sp); /* skip , */
136 if (!sp_expr(sp, n, &search_w))
138 for (i = 0; i<wrd->term_len; i++)
141 for (j = 0; j<search_w.term_len && i+j < wrd->term_len; j++)
142 if (wrd->term_buf[i+j] != search_w.term_buf[j])
144 if (j == search_w.term_len) /* match ? */
146 if (min_pos == -1 || i < min_pos)
152 if (sp->lookahead != ')')
156 min_pos = 0; /* the default if not found */
157 sprintf(num_str, "%d", min_pos);
158 wrd->term_buf = nmem_strdup(sp->nmem, num_str);
159 wrd->term_len = strlen(wrd->term_buf);
163 static int sp_expr(struct source_parser *sp, data1_node *n, RecWord *wrd)
165 if (sp->lookahead != 't')
167 if (sp->len == 4 && !memcmp(sp->tok, "data", sp->len))
169 if (n->which == DATA1N_data)
171 wrd->term_buf = n->u.data.data;
172 wrd->term_len = n->u.data.len;
176 else if (sp->len == 3 && !memcmp(sp->tok, "tag", sp->len))
178 if (n->which == DATA1N_tag)
180 wrd->term_buf = n->u.tag.tag;
181 wrd->term_len = strlen(n->u.tag.tag);
185 else if (sp->len == 4 && !memcmp(sp->tok, "attr", sp->len))
189 if (sp->lookahead != '(')
193 if (!sp_expr(sp, n, &tmp_w))
198 if (n->which == DATA1N_tag)
200 data1_xattr *p = n->u.tag.attributes;
201 while (p && strlen(p->name) != tmp_w.term_len &&
202 memcmp (p->name, tmp_w.term_buf, tmp_w.term_len))
206 wrd->term_buf = p->value;
207 wrd->term_len = strlen(p->value);
210 if (sp->lookahead != ')')
214 else if (sp->len == 5 && !memcmp(sp->tok, "first", sp->len))
216 return sp_first(sp, n, wrd);
218 else if (sp->len == 5 && !memcmp(sp->tok, "range", sp->len))
220 return sp_range(sp, n, wrd);
222 else if (sp->len > 0 && isdigit(*(unsigned char *)sp->tok))
225 wrd->term_len = sp->len;
226 b = nmem_malloc(sp->nmem, sp->len);
227 memcpy(b, sp->tok, sp->len);
231 else if (sp->len > 2 && sp->tok[0] == '\'' && sp->tok[sp->len-1] == '\'')
234 wrd->term_len = sp->len - 2;
235 b = nmem_malloc(sp->nmem, wrd->term_len);
236 memcpy(b, sp->tok+1, wrd->term_len);
249 static struct source_parser *source_parser_create(void)
251 struct source_parser *sp = xmalloc(sizeof(*sp));
253 sp->nmem = nmem_create();
257 static void source_parser_destroy(struct source_parser *sp)
261 nmem_destroy(sp->nmem);
265 static int sp_parse(struct source_parser *sp,
266 data1_node *n, RecWord *wrd, const char *src)
272 nmem_reset(sp->nmem);
275 return sp_expr(sp, n, wrd);
278 int d1_check_xpath_predicate(data1_node *n, struct xpath_predicate *p)
287 if (p->which == XPATH_PREDICATE_RELATION) {
288 if (p->u.relation.name[0]) {
289 if (*p->u.relation.name != '@') {
291 " Only attributes (@) are supported in xelm xpath predicates");
292 yaz_log(YLOG_WARN, "predicate %s ignored", p->u.relation.name);
295 attname = p->u.relation.name + 1;
297 /* looking for the attribute with a specified name */
298 for (attr = n->u.tag.attributes; attr; attr = attr->next) {
299 if (!strcmp(attr->name, attname)) {
300 if (p->u.relation.op[0]) {
301 if (*p->u.relation.op != '=') {
303 "Only '=' relation is supported (%s)",p->u.relation.op);
304 yaz_log(YLOG_WARN, "predicate %s ignored", p->u.relation.name);
307 if (!strcmp(attr->value, p->u.relation.value)) {
312 /* attribute exists, no value specified */
322 else if (p->which == XPATH_PREDICATE_BOOLEAN) {
323 if (!strcmp(p->u.boolean.op,"and")) {
324 return d1_check_xpath_predicate(n, p->u.boolean.left)
325 && d1_check_xpath_predicate(n, p->u.boolean.right);
327 else if (!strcmp(p->u.boolean.op,"or")) {
328 return (d1_check_xpath_predicate(n, p->u.boolean.left)
329 || d1_check_xpath_predicate(n, p->u.boolean.right));
331 yaz_log(YLOG_WARN, "Unknown boolean relation %s, ignored",p->u.boolean.op);
340 static int dfa_match_first(struct DFA_state **dfaar, const char *text)
342 struct DFA_state *s = dfaar[0]; /* start state */
345 const char *p = text;
348 for (c = *p++, t = s->trans, i = s->tran_no; --i >= 0; t++)
350 if (c >= t->ch[0] && c <= t->ch[1])
354 /* move to next state and return if we get a match */
362 for (t = s->trans, i = s->tran_no; --i >= 0; t++)
363 if (c >= t->ch[0] && c <= t->ch[1])
373 New function, looking for xpath "element" definitions in abs, by
374 tagpath, using a kind of ugly regxp search.The DFA was built while
375 parsing abs, so here we just go trough them and try to match
376 against the given tagpath. The first matching entry is returned.
380 Added support for enhanced xelm. Now [] predicates are considered
381 as well, when selecting indexing rules... (why the hell it's called
388 data1_termlist *xpath_termlist_by_tagpath(char *tagpath, data1_node *n)
390 data1_absyn *abs = n->root->u.root.absyn;
392 data1_xpelement *xpe = 0;
395 struct xpath_location_step *xp;
397 char *pexpr = xmalloc(strlen(tagpath)+5);
399 sprintf(pexpr, "/%s\n", tagpath);
401 for (xpe = abs->xp_elements; xpe; xpe = xpe->next)
402 xpe->match_state = -1; /* don't know if it matches yet */
404 for (xpe = abs->xp_elements; xpe; xpe = xpe->next)
407 int ok = xpe->match_state;
409 { /* don't know whether there is a match yet */
410 data1_xpelement *xpe1;
413 ok = dfa_match_first(xpe->dfa->states, pexpr);
416 /* mark this and following ones with same regexp */
417 for (xpe1 = xpe; xpe1; xpe1 = xpe1->match_next)
418 xpe1->match_state = ok;
421 assert(ok == 0 || ok == 1);
424 /* we have to check the perdicates up to the root node */
427 /* find the first tag up in the node structure */
428 for (nn = n; nn && nn->which != DATA1N_tag; nn = nn->parent)
431 /* go from inside out in the node structure, while going
432 backwards trough xpath location steps ... */
433 for (i = xpe->xpath_len - 1; i>0; i--)
435 if (!d1_check_xpath_predicate(nn, xp[i].predicate))
441 if (nn->which == DATA1N_tag)
453 return xpe->termlists;
460 1 start element (tag)
462 3 start attr (and attr-exact)
470 Now, if there is a matching xelm described in abs, for the
471 indexed element or the attribute, then the data is handled according
472 to those definitions...
474 modified by pop, 2002-12-13
477 /* add xpath index for an attribute */
478 static void index_xpath_attr(char *tag_path, char *name, char *value,
479 char *structure, struct recExtractCtrl *p,
482 wrd->index_name = ZEBRA_XPATH_ELM_BEGIN;
483 wrd->index_type = "0";
484 wrd->term_buf = tag_path;
485 wrd->term_len = strlen(tag_path);
489 wrd->index_name = ZEBRA_XPATH_ATTR_CDATA;
490 wrd->index_type = "w";
491 wrd->term_buf = value;
492 wrd->term_len = strlen(value);
495 wrd->index_name = ZEBRA_XPATH_ELM_END;
496 wrd->index_type = "0";
497 wrd->term_buf = tag_path;
498 wrd->term_len = strlen(tag_path);
503 static void mk_tag_path_full(char *tag_path_full, size_t max, data1_node *n)
508 /* we have to fetch the whole path to the data tag */
509 for (nn = n; nn; nn = nn->parent)
511 if (nn->which == DATA1N_tag)
513 size_t tlen = strlen(nn->u.tag.tag);
514 if (tlen + flen > (max - 2))
516 memcpy(tag_path_full + flen, nn->u.tag.tag, tlen);
518 tag_path_full[flen++] = '/';
521 if (nn->which == DATA1N_root)
524 tag_path_full[flen] = 0;
528 static void index_xpath(struct source_parser *sp, data1_node *n,
529 struct recExtractCtrl *p,
530 int level, RecWord *wrd,
536 char tag_path_full[1024];
537 int termlist_only = 1;
540 if (!n->root->u.root.absyn
542 n->root->u.root.absyn->xpath_indexing == DATA1_XPATH_INDEXING_ENABLE)
551 wrd->term_buf = n->u.data.data;
552 wrd->term_len = n->u.data.len;
554 mk_tag_path_full(tag_path_full, sizeof(tag_path_full), n);
556 /* If we have a matching termlist... */
557 if (n->root->u.root.absyn &&
558 (tl = xpath_termlist_by_tagpath(tag_path_full, n)))
561 for (; tl; tl = tl->next)
563 /* need to copy recword because it may be changed */
565 wrd->index_type = tl->structure;
566 memcpy(&wrd_tl, wrd, sizeof(*wrd));
568 sp_parse(sp, n, &wrd_tl, tl->source);
570 /* this is just the old fashioned attribute based index */
571 wrd_tl.index_name = tl->index_name;
572 if (p->flagShowRecords)
575 printf("%*sIdx: [%s]", (level + 1) * 4, "",
577 printf("%s %s", tl->index_name, tl->source);
579 for (i = 0; i<wrd_tl.term_len && i < 40; i++)
580 fputc(wrd_tl.term_buf[i], stdout);
582 if (wrd_tl.term_len > 40)
588 (*p->tokenAdd)(&wrd_tl);
590 if (wrd_tl.seqno > max_seqno)
591 max_seqno = wrd_tl.seqno;
594 wrd->seqno = max_seqno;
597 /* xpath indexing is done, if there was no termlist given,
598 or no ! in the termlist, and default indexing is enabled... */
599 if (!p->flagShowRecords && !termlist_only)
601 wrd->index_name = xpath_index;
602 wrd->index_type = "w";
607 mk_tag_path_full(tag_path_full, sizeof(tag_path_full), n);
609 wrd->index_type = "0";
610 wrd->term_buf = tag_path_full;
611 wrd->term_len = strlen(tag_path_full);
612 wrd->index_name = xpath_index;
613 if (p->flagShowRecords)
615 printf("%*s tag=", (level + 1) * 4, "");
616 for (i = 0; i<wrd->term_len && i < 40; i++)
617 fputc(wrd->term_buf[i], stdout);
627 (*p->tokenAdd)(wrd); /* index element pag (AKA tag path) */
629 if (xpath_is_start == 1) /* only for the starting tag... */
631 #define MAX_ATTR_COUNT 50
632 data1_termlist *tll[MAX_ATTR_COUNT];
635 for (xp = n->u.tag.attributes; xp; xp = xp->next) {
637 char attr_tag_path_full[1024];
639 /* this could be cached as well */
640 sprintf(attr_tag_path_full, "@%s/%s",
641 xp->name, tag_path_full);
643 tll[i] = xpath_termlist_by_tagpath(attr_tag_path_full,n);
647 /* attribute (no value) */
648 wrd->index_type = "0";
649 wrd->index_name = ZEBRA_XPATH_ATTR_NAME;
650 wrd->term_buf = xp->name;
651 wrd->term_len = strlen(xp->name);
658 strlen(xp->name) + strlen(xp->value) < sizeof(comb)-2)
660 /* attribute value exact */
661 strcpy(comb, xp->name);
663 strcat(comb, xp->value);
665 wrd->index_name = ZEBRA_XPATH_ATTR_NAME;
666 wrd->index_type = "0";
667 wrd->term_buf = comb;
668 wrd->term_len = strlen(comb);
678 for (xp = n->u.tag.attributes; xp; xp = xp->next) {
680 char attr_tag_path_full[1024];
683 sprintf(attr_tag_path_full, "@%s/%s",
684 xp->name, tag_path_full);
687 /* If there is a termlist given (=xelm directive) */
688 for (; tl; tl = tl->next)
692 /* add xpath index for the attribute */
693 index_xpath_attr(attr_tag_path_full, xp->name,
694 xp->value, tl->structure,
698 /* index attribute value (only path/@attr) */
701 wrd->index_name = tl->index_name;
702 wrd->index_type = tl->structure;
703 wrd->term_buf = xp->value;
704 wrd->term_len = strlen(xp->value);
710 /* if there was no termlist for the given path,
711 or the termlist didn't have a ! element, index
712 the attribute as "w" */
713 if (!xpdone && !termlist_only)
715 index_xpath_attr(attr_tag_path_full, xp->name,
716 xp->value, "w", p, wrd);
725 static void index_termlist(struct source_parser *sp, data1_node *par,
727 struct recExtractCtrl *p, int level, RecWord *wrd)
729 data1_termlist *tlist = 0;
730 data1_datatype dtype = DATA1K_string;
733 * cycle up towards the root until we find a tag with an att..
734 * this has the effect of indexing locally defined tags with
735 * the attribute of their ancestor in the record.
738 while (!par->u.tag.element)
739 if (!par->parent || !(par=get_parent_tag(p->dh, par->parent)))
741 if (!par || !(tlist = par->u.tag.element->termlists))
743 if (par->u.tag.element->tag)
744 dtype = par->u.tag.element->tag->kind;
746 for (; tlist; tlist = tlist->next)
748 /* consider source */
750 assert(tlist->source);
751 sp_parse(sp, n, wrd, tlist->source);
753 if (wrd->term_buf && wrd->term_len)
755 if (p->flagShowRecords)
758 printf("%*sIdx: [%s]", (level + 1) * 4, "",
760 printf("%s %s", tlist->index_name, tlist->source);
762 for (i = 0; i<wrd->term_len && i < 40; i++)
763 fputc(wrd->term_buf[i], stdout);
765 if (wrd->term_len > 40)
771 wrd->index_type = tlist->structure;
772 wrd->index_name = tlist->index_name;
779 static int dumpkeys_r(struct source_parser *sp,
780 data1_node *n, struct recExtractCtrl *p, int level,
783 for (; n; n = n->next)
785 if (p->flagShowRecords) /* display element description to user */
787 if (n->which == DATA1N_root)
789 printf("%*s", level * 4, "");
790 printf("Record type: '%s'\n", n->u.root.type);
792 else if (n->which == DATA1N_tag)
796 printf("%*s", level * 4, "");
797 if (!(e = n->u.tag.element))
798 printf("Local tag: '%s'\n", n->u.tag.tag);
801 printf("Elm: '%s' ", e->name);
804 data1_tag *t = e->tag;
806 printf("TagNam: '%s' ", t->names->name);
809 printf("%s[%d],", t->tagset->name, t->tagset->type);
812 if (t->which == DATA1T_numeric)
813 printf("%d)", t->value.numeric);
815 printf("'%s')", t->value.string);
822 if (n->which == DATA1N_tag)
824 index_termlist(sp, n, n, p, level, wrd);
825 /* index start tag */
826 if (n->root->u.root.absyn)
827 index_xpath(sp, n, p, level, wrd, ZEBRA_XPATH_ELM_BEGIN,
832 if (dumpkeys_r(sp, n->child, p, level + 1, wrd) < 0)
836 if (n->which == DATA1N_data)
838 data1_node *par = get_parent_tag(p->dh, n);
840 if (p->flagShowRecords)
842 printf("%*s", level * 4, "");
844 if (n->u.data.len > 256)
845 printf("'%.170s ... %.70s'\n", n->u.data.data,
846 n->u.data.data + n->u.data.len-70);
847 else if (n->u.data.len > 0)
848 printf("'%.*s'\n", n->u.data.len, n->u.data.data);
854 index_termlist(sp, par, n, p, level, wrd);
856 index_xpath(sp, n, p, level, wrd, ZEBRA_XPATH_CDATA,
860 if (n->which == DATA1N_tag)
863 index_xpath(sp, n, p, level, wrd, ZEBRA_XPATH_ELM_END,
867 if (p->flagShowRecords && n->which == DATA1N_root)
869 printf("%*s-------------\n\n", level * 4, "");
875 static int dumpkeys(data1_node *n, struct recExtractCtrl *p, RecWord *wrd)
877 struct source_parser *sp = source_parser_create();
878 int r = dumpkeys_r(sp, n, p, 0, wrd);
879 source_parser_destroy(sp);
883 int grs_extract_tree(struct recExtractCtrl *p, data1_node *n)
887 if (n->u.root.absyn && n->u.root.absyn->oid)
888 (*p->schemaAdd)(p, n->u.root.absyn->oid);
891 /* data1_pr_tree(p->dh, n, stdout); */
893 return dumpkeys(n, p, &wrd);
896 static int grs_extract_sub(void *clientData, struct recExtractCtrl *p,
898 data1_node *(*grs_read)(struct grs_read_info *))
901 struct grs_read_info gri;
904 gri.stream = p->stream;
907 gri.clientData = clientData;
909 n = (*grs_read)(&gri);
911 return RECCTRL_EXTRACT_EOF;
912 if (n->u.root.absyn && n->u.root.absyn->oid)
913 (*p->schemaAdd)(p, n->u.root.absyn->oid);
914 data1_concat_text(p->dh, mem, n);
916 /* ensure our data1 tree is UTF-8 */
917 data1_iconv(p->dh, mem, n, "UTF-8", data1_get_encoding(p->dh, n));
920 data1_remove_idzebra_subtree(p->dh, n);
923 data1_pr_tree(p->dh, n, stdout);
927 if (dumpkeys(n, p, &wrd) < 0)
929 return RECCTRL_EXTRACT_ERROR_GENERIC;
931 return RECCTRL_EXTRACT_OK;
934 int zebra_grs_extract(void *clientData, struct recExtractCtrl *p,
935 data1_node *(*grs_read)(struct grs_read_info *))
938 NMEM mem = nmem_create();
939 ret = grs_extract_sub(clientData, p, mem, grs_read);
945 * Return: -1: Nothing done. 0: Ok. >0: Bib-1 diagnostic.
947 static int process_comp(data1_handle dh, data1_node *n, Z_RecordComposition *c,
948 char **addinfo, ODR o)
950 data1_esetname *eset;
956 case Z_RecordComp_simple:
957 if (c->u.simple->which != Z_ElementSetNames_generic)
958 return 26; /* only generic form supported. Fix this later */
959 if (!(eset = data1_getesetbyname(dh, n->u.root.absyn,
960 c->u.simple->u.generic)))
962 yaz_log(YLOG_LOG, "Unknown esetname '%s'", c->u.simple->u.generic);
963 *addinfo = odr_strdup(o, c->u.simple->u.generic);
964 return 25; /* invalid esetname */
966 yaz_log(YLOG_DEBUG, "Esetname '%s' in simple compspec",
967 c->u.simple->u.generic);
970 case Z_RecordComp_complex:
971 if (c->u.complex->generic)
973 /* insert check for schema */
974 if ((p = c->u.complex->generic->elementSpec))
978 case Z_ElementSpec_elementSetName:
980 data1_getesetbyname(dh, n->u.root.absyn,
981 p->u.elementSetName)))
983 yaz_log(YLOG_DEBUG, "Unknown esetname '%s'",
984 p->u.elementSetName);
985 *addinfo = odr_strdup(o, p->u.elementSetName);
986 return 25; /* invalid esetname */
988 yaz_log(YLOG_DEBUG, "Esetname '%s' in complex compspec",
989 p->u.elementSetName);
992 case Z_ElementSpec_externalSpec:
993 if (p->u.externalSpec->which == Z_External_espec1)
995 yaz_log(YLOG_DEBUG, "Got Espec-1");
996 espec = p->u.externalSpec-> u.espec1;
1000 yaz_log(YLOG_LOG, "Unknown external espec.");
1001 return 25; /* bad. what is proper diagnostic? */
1008 return 26; /* fix */
1012 yaz_log(YLOG_DEBUG, "Element: Espec-1 match");
1013 return data1_doespec1(dh, n, espec);
1017 yaz_log(YLOG_DEBUG, "Element: all match");
1022 /* Add Zebra info in separate namespace ...
1025 <metadata xmlns="http://www.indexdata.dk/zebra/">
1027 <localnumber>447</localnumber>
1028 <filename>records/genera.xml</filename>
1033 static void zebra_xml_metadata(struct recRetrieveCtrl *p, data1_node *top,
1036 const char *idzebra_ns[3];
1037 const char *i2 = "\n ";
1038 const char *i4 = "\n ";
1041 idzebra_ns[0] = "xmlns";
1042 idzebra_ns[1] = "http://www.indexdata.dk/zebra/";
1045 data1_mk_text(p->dh, mem, i2, top);
1047 n = data1_mk_tag(p->dh, mem, "idzebra", idzebra_ns, top);
1049 data1_mk_text(p->dh, mem, "\n", top);
1051 data1_mk_text(p->dh, mem, i4, n);
1053 data1_mk_tag_data_int(p->dh, n, "size", p->recordSize, mem);
1057 data1_mk_text(p->dh, mem, i4, n);
1058 data1_mk_tag_data_int(p->dh, n, "score", p->score, mem);
1060 data1_mk_text(p->dh, mem, i4, n);
1061 data1_mk_tag_data_zint(p->dh, n, "localnumber", p->localno, mem);
1064 data1_mk_text(p->dh, mem, i4, n);
1065 data1_mk_tag_data_text(p->dh, n, "filename", p->fname, mem);
1067 data1_mk_text(p->dh, mem, i2, n);
1070 int zebra_grs_retrieve(void *clientData, struct recRetrieveCtrl *p,
1071 data1_node *(*grs_read)(struct grs_read_info *))
1073 data1_node *node = 0, *onode = 0, *top;
1076 int res, selected = 0;
1078 struct grs_read_info gri;
1079 const char *tagname;
1081 const Odr_oid *requested_schema = 0;
1082 data1_marctab *marctab;
1085 mem = nmem_create();
1086 gri.stream = p->stream;
1089 gri.clientData = clientData;
1091 yaz_log(YLOG_DEBUG, "grs_retrieve");
1092 node = (*grs_read)(&gri);
1095 p->diagnostic = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
1099 data1_concat_text(p->dh, mem, node);
1101 data1_remove_idzebra_subtree(p->dh, node);
1104 data1_pr_tree(p->dh, node, stdout);
1106 top = data1_get_root_tag(p->dh, node);
1108 yaz_log(YLOG_DEBUG, "grs_retrieve: size");
1109 tagname = data1_systag_lookup(node->u.root.absyn, "size", "size");
1111 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1113 dnew->u.data.what = DATA1I_text;
1114 dnew->u.data.data = dnew->lbuf;
1115 sprintf(dnew->u.data.data, "%d", p->recordSize);
1116 dnew->u.data.len = strlen(dnew->u.data.data);
1119 tagname = data1_systag_lookup(node->u.root.absyn, "rank", "rank");
1120 if (tagname && p->score >= 0 &&
1121 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1123 yaz_log(YLOG_DEBUG, "grs_retrieve: %s", tagname);
1124 dnew->u.data.what = DATA1I_num;
1125 dnew->u.data.data = dnew->lbuf;
1126 sprintf(dnew->u.data.data, "%d", p->score);
1127 dnew->u.data.len = strlen(dnew->u.data.data);
1130 tagname = data1_systag_lookup(node->u.root.absyn, "sysno",
1131 "localControlNumber");
1132 if (tagname && p->localno > 0 &&
1133 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1135 yaz_log(YLOG_DEBUG, "grs_retrieve: %s", tagname);
1136 dnew->u.data.what = DATA1I_text;
1137 dnew->u.data.data = dnew->lbuf;
1139 sprintf(dnew->u.data.data, ZINT_FORMAT, p->localno);
1140 dnew->u.data.len = strlen(dnew->u.data.data);
1143 if (!p->input_format)
1144 { /* SUTRS is default input_format */
1145 p->input_format = yaz_oid_recsyn_sutrs;
1147 assert(p->input_format);
1149 if (!oid_oidcmp(p->input_format, yaz_oid_recsyn_xml))
1150 zebra_xml_metadata(p, top, mem);
1153 data1_pr_tree(p->dh, node, stdout);
1155 if (p->comp && p->comp->which == Z_RecordComp_complex &&
1156 p->comp->u.complex->generic &&
1157 p->comp->u.complex->generic->which == Z_Schema_oid &&
1158 p->comp->u.complex->generic->schema.oid)
1160 requested_schema = p->comp->u.complex->generic->schema.oid;
1162 /* If schema has been specified, map if possible, then check that
1163 * we got the right one
1165 if (requested_schema)
1167 yaz_log(YLOG_DEBUG, "grs_retrieve: schema mapping");
1168 for (map = node->u.root.absyn->maptabs; map; map = map->next)
1170 // if (map->target_absyn_ref == requested_schema)
1171 if (!oid_oidcmp(map->oid, requested_schema))
1174 if (!(node = data1_map_record(p->dh, onode, map, mem)))
1176 p->diagnostic = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
1183 if (node->u.root.absyn
1184 && oid_oidcmp(requested_schema, node->u.root.absyn->oid))
1186 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1192 * Does the requested format match a known syntax-mapping? (this reflects
1193 * the overlap of schema and formatting which is inherent in the MARC
1196 yaz_log(YLOG_DEBUG, "grs_retrieve: syntax mapping");
1197 if (node->u.root.absyn)
1198 for (map = node->u.root.absyn->maptabs; map; map = map->next)
1200 if (!oid_oidcmp(map->oid, p->input_format))
1203 if (!(node = data1_map_record(p->dh, onode, map, mem)))
1205 p->diagnostic = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
1212 yaz_log(YLOG_DEBUG, "grs_retrieve: schemaIdentifier");
1213 if (node->u.root.absyn && node->u.root.absyn->oid
1214 && !oid_oidcmp(p->input_format, yaz_oid_recsyn_grs_1))
1216 char oid_str[OID_STR_MAX];
1217 char *dot_str = oid_oid_to_dotstring(node->u.root.absyn->oid, oid_str);
1219 if (dot_str && (dnew = data1_mk_tag_data_wd(p->dh, top,
1220 "schemaIdentifier", mem)))
1222 dnew->u.data.what = DATA1I_oid;
1223 dnew->u.data.data = (char *) nmem_strdup(mem, dot_str);
1224 dnew->u.data.len = strlen(dot_str);
1228 yaz_log(YLOG_DEBUG, "grs_retrieve: element spec");
1229 if (p->comp && (res = process_comp(p->dh, node, p->comp, &p->addinfo,
1232 p->diagnostic = res;
1236 else if (p->comp && !res)
1240 data1_pr_tree(p->dh, node, stdout);
1242 yaz_log(YLOG_DEBUG, "grs_retrieve: transfer syntax mapping");
1244 p->output_format = p->input_format;
1246 assert(p->input_format);
1247 if (!oid_oidcmp(p->input_format, yaz_oid_recsyn_xml))
1250 data1_pr_tree(p->dh, node, stdout);
1252 /* default output encoding for XML is UTF-8 */
1253 data1_iconv(p->dh, mem, node,
1254 p->encoding ? p->encoding : "UTF-8",
1255 data1_get_encoding(p->dh, node));
1257 if (!(p->rec_buf = data1_nodetoidsgml(p->dh, node, selected,
1259 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1262 char *new_buf = (char*) odr_malloc(p->odr, p->rec_len);
1263 memcpy(new_buf, p->rec_buf, p->rec_len);
1264 p->rec_buf = new_buf;
1267 else if (!oid_oidcmp(p->input_format, yaz_oid_recsyn_grs_1))
1269 data1_iconv(p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1271 if (!(p->rec_buf = data1_nodetogr(p->dh, node, selected,
1273 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1277 else if (!oid_oidcmp(p->input_format, yaz_oid_recsyn_explain))
1279 /* ensure our data1 tree is UTF-8 */
1280 data1_iconv(p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1282 if (!(p->rec_buf = data1_nodetoexplain(p->dh, node, selected,
1284 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1288 else if (!oid_oidcmp(p->input_format, yaz_oid_recsyn_summary))
1290 /* ensure our data1 tree is UTF-8 */
1291 data1_iconv(p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1292 if (!(p->rec_buf = data1_nodetosummary(p->dh, node, selected,
1294 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1298 else if (!oid_oidcmp(p->input_format, yaz_oid_recsyn_sutrs))
1301 data1_iconv(p->dh, mem, node, p->encoding,
1302 data1_get_encoding(p->dh, node));
1303 if (!(p->rec_buf = data1_nodetobuf(p->dh, node, selected,
1305 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1308 char *new_buf = (char*) odr_malloc(p->odr, p->rec_len);
1309 memcpy(new_buf, p->rec_buf, p->rec_len);
1310 p->rec_buf = new_buf;
1313 else if (!oid_oidcmp(p->input_format, yaz_oid_recsyn_soif))
1316 data1_iconv(p->dh, mem, node, p->encoding,
1317 data1_get_encoding(p->dh, node));
1318 if (!(p->rec_buf = data1_nodetosoif(p->dh, node, selected,
1320 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1323 char *new_buf = (char*) odr_malloc(p->odr, p->rec_len);
1324 memcpy(new_buf, p->rec_buf, p->rec_len);
1325 p->rec_buf = new_buf;
1330 if (!node->u.root.absyn)
1331 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1334 for (marctab = node->u.root.absyn->marc; marctab;
1335 marctab = marctab->next)
1336 if (marctab->oid && !oid_oidcmp(marctab->oid, p->input_format))
1339 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1343 data1_iconv(p->dh, mem, node, p->encoding,
1344 data1_get_encoding(p->dh, node));
1345 if (!(p->rec_buf = data1_nodetomarc(p->dh, marctab, node,
1346 selected, &p->rec_len)))
1347 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1350 char *new_buf = (char*) odr_malloc(p->odr, p->rec_len);
1351 memcpy(new_buf, p->rec_buf, p->rec_len);
1352 p->rec_buf = new_buf;
1364 * indent-tabs-mode: nil
1366 * vim: shiftwidth=4 tabstop=8 expandtab