1 /* $Id: recgrs.c,v 1.15 2007-02-02 12:16:38 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>
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 yaz_log(YLOG_DEBUG, "Got it");
454 return xpe->termlists;
461 1 start element (tag)
463 3 start attr (and attr-exact)
471 Now, if there is a matching xelm described in abs, for the
472 indexed element or the attribute, then the data is handled according
473 to those definitions...
475 modified by pop, 2002-12-13
478 /* add xpath index for an attribute */
479 static void index_xpath_attr (char *tag_path, char *name, char *value,
480 char *structure, struct recExtractCtrl *p,
483 wrd->index_name = ZEBRA_XPATH_ELM_BEGIN;
484 wrd->index_type = '0';
485 wrd->term_buf = tag_path;
486 wrd->term_len = strlen(tag_path);
490 wrd->index_name = ZEBRA_XPATH_ATTR_CDATA;
491 wrd->index_type = 'w';
492 wrd->term_buf = value;
493 wrd->term_len = strlen(value);
496 wrd->index_name = ZEBRA_XPATH_ELM_END;
497 wrd->index_type = '0';
498 wrd->term_buf = tag_path;
499 wrd->term_len = strlen(tag_path);
504 static void mk_tag_path_full(char *tag_path_full, size_t max, data1_node *n)
509 /* we have to fetch the whole path to the data tag */
510 for (nn = n; nn; nn = nn->parent)
512 if (nn->which == DATA1N_tag)
514 size_t tlen = strlen(nn->u.tag.tag);
515 if (tlen + flen > (max - 2))
517 memcpy (tag_path_full + flen, nn->u.tag.tag, tlen);
519 tag_path_full[flen++] = '/';
522 if (nn->which == DATA1N_root)
525 tag_path_full[flen] = 0;
529 static void index_xpath(struct source_parser *sp, data1_node *n,
530 struct recExtractCtrl *p,
531 int level, RecWord *wrd,
537 char tag_path_full[1024];
538 int termlist_only = 1;
542 if (!n->root->u.root.absyn
544 n->root->u.root.absyn->xpath_indexing == DATA1_XPATH_INDEXING_ENABLE)
553 wrd->term_buf = n->u.data.data;
554 wrd->term_len = n->u.data.len;
557 mk_tag_path_full(tag_path_full, sizeof(tag_path_full), n);
559 /* If we have a matching termlist... */
560 if (n->root->u.root.absyn &&
561 (tl = xpath_termlist_by_tagpath(tag_path_full, n)))
564 for (; tl; tl = tl->next)
566 /* need to copy recword because it may be changed */
568 wrd->index_type = *tl->structure;
569 memcpy (&wrd_tl, wrd, sizeof(*wrd));
571 sp_parse(sp, n, &wrd_tl, tl->source);
573 /* this is just the old fashioned attribute based index */
574 wrd_tl.index_name = tl->index_name;
575 if (p->flagShowRecords)
578 printf("%*sIdx: [%s]", (level + 1) * 4, "",
580 printf("%s %s", tl->index_name, tl->source);
581 printf (" XData:\"");
582 for (i = 0; i<wrd_tl.term_len && i < 40; i++)
583 fputc (wrd_tl.term_buf[i], stdout);
585 if (wrd_tl.term_len > 40)
587 fputc ('\n', stdout);
591 (*p->tokenAdd)(&wrd_tl);
593 if (wrd_tl.seqno > max_seqno)
594 max_seqno = wrd_tl.seqno;
597 wrd->seqno = max_seqno;
600 /* xpath indexing is done, if there was no termlist given,
601 or no ! in the termlist, and default indexing is enabled... */
602 if (!p->flagShowRecords && !xpdone && !termlist_only)
604 wrd->index_name = xpath_index;
605 wrd->index_type = 'w';
612 mk_tag_path_full(tag_path_full, sizeof(tag_path_full), n);
614 wrd->index_type = '0';
615 wrd->term_buf = tag_path_full;
616 wrd->term_len = strlen(tag_path_full);
617 wrd->index_name = xpath_index;
618 if (p->flagShowRecords)
620 printf("%*s tag=", (level + 1) * 4, "");
621 for (i = 0; i<wrd->term_len && i < 40; i++)
622 fputc (wrd->term_buf[i], stdout);
631 (*p->tokenAdd)(wrd); /* index element pag (AKA tag path) */
633 if (xpath_is_start == 1) /* only for the starting tag... */
635 #define MAX_ATTR_COUNT 50
636 data1_termlist *tll[MAX_ATTR_COUNT];
639 for (xp = n->u.tag.attributes; xp; xp = xp->next) {
641 char attr_tag_path_full[1024];
643 /* this could be cached as well */
644 sprintf (attr_tag_path_full, "@%s/%s",
645 xp->name, tag_path_full);
647 tll[i] = xpath_termlist_by_tagpath(attr_tag_path_full,n);
649 /* attribute (no value) */
650 wrd->index_type = '0';
651 wrd->index_name = ZEBRA_XPATH_ATTR_NAME;
652 wrd->term_buf = xp->name;
653 wrd->term_len = strlen(xp->name);
660 strlen(xp->name) + strlen(xp->value) < sizeof(comb)-2)
662 /* attribute value exact */
663 strcpy (comb, xp->name);
665 strcat (comb, xp->value);
667 wrd->index_name = ZEBRA_XPATH_ATTR_NAME;
668 wrd->index_type = '0';
669 wrd->term_buf = comb;
670 wrd->term_len = strlen(comb);
679 for (xp = n->u.tag.attributes; xp; xp = xp->next) {
681 char attr_tag_path_full[1024];
684 sprintf (attr_tag_path_full, "@%s/%s",
685 xp->name, tag_path_full);
689 /* If there is a termlist given (=xelm directive) */
690 for (; tl; tl = tl->next)
694 /* add xpath index for the attribute */
695 index_xpath_attr (attr_tag_path_full, xp->name,
696 xp->value, tl->structure,
700 /* index attribute value (only path/@attr) */
703 wrd->index_name = tl->index_name;
704 wrd->index_type = *tl->structure;
705 wrd->term_buf = xp->value;
706 wrd->term_len = strlen(xp->value);
712 /* if there was no termlist for the given path,
713 or the termlist didn't have a ! element, index
714 the attribute as "w" */
715 if ((!xpdone) && (!termlist_only))
717 index_xpath_attr (attr_tag_path_full, xp->name,
718 xp->value, "w", p, wrd);
727 static void index_termlist (struct source_parser *sp, data1_node *par,
729 struct recExtractCtrl *p, int level, RecWord *wrd)
731 data1_termlist *tlist = 0;
732 data1_datatype dtype = DATA1K_string;
735 * cycle up towards the root until we find a tag with an att..
736 * this has the effect of indexing locally defined tags with
737 * the attribute of their ancestor in the record.
740 while (!par->u.tag.element)
741 if (!par->parent || !(par=get_parent_tag(p->dh, par->parent)))
743 if (!par || !(tlist = par->u.tag.element->termlists))
745 if (par->u.tag.element->tag)
746 dtype = par->u.tag.element->tag->kind;
748 for (; tlist; tlist = tlist->next)
750 /* consider source */
752 assert(tlist->source);
753 sp_parse(sp, n, wrd, tlist->source);
755 if (wrd->term_buf && wrd->term_len)
757 if (p->flagShowRecords)
760 printf("%*sIdx: [%s]", (level + 1) * 4, "",
762 printf("%s %s", tlist->index_name, tlist->source);
763 printf (" XData:\"");
764 for (i = 0; i<wrd->term_len && i < 40; i++)
765 fputc (wrd->term_buf[i], stdout);
767 if (wrd->term_len > 40)
769 fputc ('\n', stdout);
773 wrd->index_type = *tlist->structure;
774 wrd->index_name = tlist->index_name;
781 static int dumpkeys_r(struct source_parser *sp,
782 data1_node *n, struct recExtractCtrl *p, int level,
785 for (; n; n = n->next)
787 if (p->flagShowRecords) /* display element description to user */
789 if (n->which == DATA1N_root)
791 printf("%*s", level * 4, "");
792 printf("Record type: '%s'\n", n->u.root.type);
794 else if (n->which == DATA1N_tag)
798 printf("%*s", level * 4, "");
799 if (!(e = n->u.tag.element))
800 printf("Local tag: '%s'\n", n->u.tag.tag);
803 printf("Elm: '%s' ", e->name);
806 data1_tag *t = e->tag;
808 printf("TagNam: '%s' ", t->names->name);
811 printf("%s[%d],", t->tagset->name, t->tagset->type);
814 if (t->which == DATA1T_numeric)
815 printf("%d)", t->value.numeric);
817 printf("'%s')", t->value.string);
824 if (n->which == DATA1N_tag)
826 index_termlist(sp, n, n, p, level, wrd);
827 /* index start tag */
828 if (n->root->u.root.absyn)
829 index_xpath(sp, n, p, level, wrd, ZEBRA_XPATH_ELM_BEGIN,
834 if (dumpkeys_r(sp, n->child, p, level + 1, wrd) < 0)
838 if (n->which == DATA1N_data)
840 data1_node *par = get_parent_tag(p->dh, n);
842 if (p->flagShowRecords)
844 printf("%*s", level * 4, "");
846 if (n->u.data.len > 256)
847 printf("'%.170s ... %.70s'\n", n->u.data.data,
848 n->u.data.data + n->u.data.len-70);
849 else if (n->u.data.len > 0)
850 printf("'%.*s'\n", n->u.data.len, n->u.data.data);
856 index_termlist(sp, par, n, p, level, wrd);
858 index_xpath(sp, n, p, level, wrd, ZEBRA_XPATH_CDATA,
862 if (n->which == DATA1N_tag)
865 index_xpath(sp, n, p, level, wrd, ZEBRA_XPATH_ELM_END,
869 if (p->flagShowRecords && n->which == DATA1N_root)
871 printf("%*s-------------\n\n", level * 4, "");
877 static int dumpkeys(data1_node *n, struct recExtractCtrl *p, RecWord *wrd)
879 struct source_parser *sp = source_parser_create();
880 int r = dumpkeys_r(sp, n, p, 0, wrd);
881 source_parser_destroy(sp);
885 int grs_extract_tree(struct recExtractCtrl *p, data1_node *n)
888 int oidtmp[OID_SIZE];
891 oe.proto = PROTO_Z3950;
892 oe.oclass = CLASS_SCHEMA;
895 oe.value = n->u.root.absyn->reference;
897 if ((oid_ent_to_oid (&oe, oidtmp)))
898 (*p->schemaAdd)(p, oidtmp);
902 /* data1_pr_tree(p->dh, n, stdout); */
904 return dumpkeys(n, p, &wrd);
907 static int grs_extract_sub(void *clientData, struct recExtractCtrl *p,
909 data1_node *(*grs_read)(struct grs_read_info *))
912 struct grs_read_info gri;
914 int oidtmp[OID_SIZE];
917 gri.stream = p->stream;
920 gri.clientData = clientData;
922 n = (*grs_read)(&gri);
924 return RECCTRL_EXTRACT_EOF;
925 oe.proto = PROTO_Z3950;
926 oe.oclass = CLASS_SCHEMA;
928 if (!n->u.root.absyn)
929 return RECCTRL_EXTRACT_ERROR;
933 oe.value = n->u.root.absyn->reference;
934 if ((oid_ent_to_oid (&oe, oidtmp)))
935 (*p->schemaAdd)(p, oidtmp);
937 data1_concat_text(p->dh, mem, n);
939 /* ensure our data1 tree is UTF-8 */
940 data1_iconv (p->dh, mem, n, "UTF-8", data1_get_encoding(p->dh, n));
943 data1_remove_idzebra_subtree (p->dh, n);
946 data1_pr_tree (p->dh, n, stdout);
950 if (dumpkeys(n, p, &wrd) < 0)
952 return RECCTRL_EXTRACT_ERROR_GENERIC;
954 return RECCTRL_EXTRACT_OK;
957 int zebra_grs_extract(void *clientData, struct recExtractCtrl *p,
958 data1_node *(*grs_read)(struct grs_read_info *))
961 NMEM mem = nmem_create ();
962 ret = grs_extract_sub(clientData, p, mem, grs_read);
968 * Return: -1: Nothing done. 0: Ok. >0: Bib-1 diagnostic.
970 static int process_comp(data1_handle dh, data1_node *n, Z_RecordComposition *c,
971 char **addinfo, ODR o)
973 data1_esetname *eset;
979 case Z_RecordComp_simple:
980 if (c->u.simple->which != Z_ElementSetNames_generic)
981 return 26; /* only generic form supported. Fix this later */
982 if (!(eset = data1_getesetbyname(dh, n->u.root.absyn,
983 c->u.simple->u.generic)))
985 yaz_log(YLOG_LOG, "Unknown esetname '%s'", c->u.simple->u.generic);
986 *addinfo = odr_strdup(o, c->u.simple->u.generic);
987 return 25; /* invalid esetname */
989 yaz_log(YLOG_DEBUG, "Esetname '%s' in simple compspec",
990 c->u.simple->u.generic);
993 case Z_RecordComp_complex:
994 if (c->u.complex->generic)
996 /* insert check for schema */
997 if ((p = c->u.complex->generic->elementSpec))
1001 case Z_ElementSpec_elementSetName:
1003 data1_getesetbyname(dh, n->u.root.absyn,
1004 p->u.elementSetName)))
1006 yaz_log(YLOG_DEBUG, "Unknown esetname '%s'",
1007 p->u.elementSetName);
1008 *addinfo = odr_strdup(o, p->u.elementSetName);
1009 return 25; /* invalid esetname */
1011 yaz_log(YLOG_DEBUG, "Esetname '%s' in complex compspec",
1012 p->u.elementSetName);
1015 case Z_ElementSpec_externalSpec:
1016 if (p->u.externalSpec->which == Z_External_espec1)
1018 yaz_log(YLOG_DEBUG, "Got Espec-1");
1019 espec = p->u.externalSpec-> u.espec1;
1023 yaz_log(YLOG_LOG, "Unknown external espec.");
1024 return 25; /* bad. what is proper diagnostic? */
1031 return 26; /* fix */
1035 yaz_log(YLOG_DEBUG, "Element: Espec-1 match");
1036 return data1_doespec1(dh, n, espec);
1040 yaz_log(YLOG_DEBUG, "Element: all match");
1045 /* Add Zebra info in separate namespace ...
1048 <metadata xmlns="http://www.indexdata.dk/zebra/">
1050 <localnumber>447</localnumber>
1051 <filename>records/genera.xml</filename>
1056 static void zebra_xml_metadata (struct recRetrieveCtrl *p, data1_node *top,
1059 const char *idzebra_ns[3];
1060 const char *i2 = "\n ";
1061 const char *i4 = "\n ";
1064 idzebra_ns[0] = "xmlns";
1065 idzebra_ns[1] = "http://www.indexdata.dk/zebra/";
1068 data1_mk_text (p->dh, mem, i2, top);
1070 n = data1_mk_tag (p->dh, mem, "idzebra", idzebra_ns, top);
1072 data1_mk_text (p->dh, mem, "\n", top);
1074 data1_mk_text (p->dh, mem, i4, n);
1076 data1_mk_tag_data_int (p->dh, n, "size", p->recordSize, mem);
1080 data1_mk_text (p->dh, mem, i4, n);
1081 data1_mk_tag_data_int (p->dh, n, "score", p->score, mem);
1083 data1_mk_text (p->dh, mem, i4, n);
1084 data1_mk_tag_data_zint (p->dh, n, "localnumber", p->localno, mem);
1087 data1_mk_text (p->dh, mem, i4, n);
1088 data1_mk_tag_data_text(p->dh, n, "filename", p->fname, mem);
1090 data1_mk_text (p->dh, mem, i2, n);
1093 int zebra_grs_retrieve(void *clientData, struct recRetrieveCtrl *p,
1094 data1_node *(*grs_read)(struct grs_read_info *))
1096 data1_node *node = 0, *onode = 0, *top;
1099 int res, selected = 0;
1101 struct grs_read_info gri;
1102 const char *tagname;
1104 int requested_schema = VAL_NONE;
1105 data1_marctab *marctab;
1108 mem = nmem_create();
1109 gri.stream = p->stream;
1112 gri.clientData = clientData;
1114 yaz_log(YLOG_DEBUG, "grs_retrieve");
1115 node = (*grs_read)(&gri);
1118 p->diagnostic = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
1122 data1_concat_text(p->dh, mem, node);
1124 data1_remove_idzebra_subtree (p->dh, node);
1127 data1_pr_tree (p->dh, node, stdout);
1129 top = data1_get_root_tag (p->dh, node);
1131 yaz_log(YLOG_DEBUG, "grs_retrieve: size");
1132 tagname = data1_systag_lookup(node->u.root.absyn, "size", "size");
1134 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1136 dnew->u.data.what = DATA1I_text;
1137 dnew->u.data.data = dnew->lbuf;
1138 sprintf(dnew->u.data.data, "%d", p->recordSize);
1139 dnew->u.data.len = strlen(dnew->u.data.data);
1142 tagname = data1_systag_lookup(node->u.root.absyn, "rank", "rank");
1143 if (tagname && p->score >= 0 &&
1144 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1146 yaz_log(YLOG_DEBUG, "grs_retrieve: %s", tagname);
1147 dnew->u.data.what = DATA1I_num;
1148 dnew->u.data.data = dnew->lbuf;
1149 sprintf(dnew->u.data.data, "%d", p->score);
1150 dnew->u.data.len = strlen(dnew->u.data.data);
1153 tagname = data1_systag_lookup(node->u.root.absyn, "sysno",
1154 "localControlNumber");
1155 if (tagname && p->localno > 0 &&
1156 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1158 yaz_log(YLOG_DEBUG, "grs_retrieve: %s", tagname);
1159 dnew->u.data.what = DATA1I_text;
1160 dnew->u.data.data = dnew->lbuf;
1162 sprintf(dnew->u.data.data, ZINT_FORMAT, p->localno);
1163 dnew->u.data.len = strlen(dnew->u.data.data);
1166 if (p->input_format == VAL_TEXT_XML)
1167 zebra_xml_metadata (p, top, mem);
1170 data1_pr_tree (p->dh, node, stdout);
1172 if (p->comp && p->comp->which == Z_RecordComp_complex &&
1173 p->comp->u.complex->generic &&
1174 p->comp->u.complex->generic->which == Z_Schema_oid &&
1175 p->comp->u.complex->generic->schema.oid)
1177 oident *oe = oid_getentbyoid (p->comp->u.complex->generic->schema.oid);
1179 requested_schema = oe->value;
1181 /* If schema has been specified, map if possible, then check that
1182 * we got the right one
1184 if (requested_schema != VAL_NONE)
1186 yaz_log(YLOG_DEBUG, "grs_retrieve: schema mapping");
1187 for (map = node->u.root.absyn->maptabs; map; map = map->next)
1189 if (map->target_absyn_ref == requested_schema)
1192 if (!(node = data1_map_record(p->dh, onode, map, mem)))
1194 p->diagnostic = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
1201 if (node->u.root.absyn &&
1202 requested_schema != node->u.root.absyn->reference)
1204 p->diagnostic = 238;
1210 * Does the requested format match a known syntax-mapping? (this reflects
1211 * the overlap of schema and formatting which is inherent in the MARC
1214 yaz_log(YLOG_DEBUG, "grs_retrieve: syntax mapping");
1215 if (node->u.root.absyn)
1216 for (map = node->u.root.absyn->maptabs; map; map = map->next)
1218 if (map->target_absyn_ref == p->input_format)
1221 if (!(node = data1_map_record(p->dh, onode, map, mem)))
1223 p->diagnostic = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
1230 yaz_log(YLOG_DEBUG, "grs_retrieve: schemaIdentifier");
1231 if (node->u.root.absyn &&
1232 node->u.root.absyn->reference != VAL_NONE &&
1233 p->input_format == VAL_GRS1)
1237 int oidtmp[OID_SIZE];
1239 oe.proto = PROTO_Z3950;
1240 oe.oclass = CLASS_SCHEMA;
1241 oe.value = node->u.root.absyn->reference;
1243 if ((oid = oid_ent_to_oid (&oe, oidtmp)))
1246 data1_handle dh = p->dh;
1250 for (ii = oid; *ii >= 0; ii++)
1254 sprintf(p, "%d", *ii);
1257 if ((dnew = data1_mk_tag_data_wd(dh, top,
1258 "schemaIdentifier", mem)))
1260 dnew->u.data.what = DATA1I_oid;
1261 dnew->u.data.data = (char *) nmem_malloc(mem, p - tmp);
1262 memcpy(dnew->u.data.data, tmp, p - tmp);
1263 dnew->u.data.len = p - tmp;
1268 yaz_log(YLOG_DEBUG, "grs_retrieve: element spec");
1269 if (p->comp && (res = process_comp(p->dh, node, p->comp, &p->addinfo,
1272 p->diagnostic = res;
1276 else if (p->comp && !res)
1280 data1_pr_tree (p->dh, node, stdout);
1282 yaz_log(YLOG_DEBUG, "grs_retrieve: transfer syntax mapping");
1283 switch (p->output_format = (p->input_format != VAL_NONE ?
1284 p->input_format : VAL_SUTRS))
1288 data1_pr_tree (p->dh, node, stdout);
1290 /* default output encoding for XML is UTF-8 */
1291 data1_iconv (p->dh, mem, node,
1292 p->encoding ? p->encoding : "UTF-8",
1293 data1_get_encoding(p->dh, node));
1295 if (!(p->rec_buf = data1_nodetoidsgml(p->dh, node, selected,
1297 p->diagnostic = 238;
1300 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1301 memcpy (new_buf, p->rec_buf, p->rec_len);
1302 p->rec_buf = new_buf;
1306 data1_iconv (p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1308 if (!(p->rec_buf = data1_nodetogr(p->dh, node, selected,
1310 p->diagnostic = 238; /* not available in requested syntax */
1315 /* ensure our data1 tree is UTF-8 */
1316 data1_iconv (p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1318 if (!(p->rec_buf = data1_nodetoexplain(p->dh, node, selected,
1320 p->diagnostic = 238;
1325 /* ensure our data1 tree is UTF-8 */
1326 data1_iconv (p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1327 if (!(p->rec_buf = data1_nodetosummary(p->dh, node, selected,
1329 p->diagnostic = 238;
1335 data1_iconv (p->dh, mem, node, p->encoding,
1336 data1_get_encoding(p->dh, node));
1337 if (!(p->rec_buf = data1_nodetobuf(p->dh, node, selected,
1339 p->diagnostic = 238;
1342 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1343 memcpy (new_buf, p->rec_buf, p->rec_len);
1344 p->rec_buf = new_buf;
1349 data1_iconv (p->dh, mem, node, p->encoding,
1350 data1_get_encoding(p->dh, node));
1351 if (!(p->rec_buf = data1_nodetosoif(p->dh, node, selected,
1353 p->diagnostic = 238;
1356 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1357 memcpy (new_buf, p->rec_buf, p->rec_len);
1358 p->rec_buf = new_buf;
1362 if (!node->u.root.absyn)
1364 p->diagnostic = 238;
1367 for (marctab = node->u.root.absyn->marc; marctab;
1368 marctab = marctab->next)
1369 if (marctab->reference == p->input_format)
1373 p->diagnostic = 238;
1377 data1_iconv (p->dh, mem, node, p->encoding,
1378 data1_get_encoding(p->dh, node));
1379 if (!(p->rec_buf = data1_nodetomarc(p->dh, marctab, node,
1380 selected, &p->rec_len)))
1381 p->diagnostic = 238;
1384 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1385 memcpy (new_buf, p->rec_buf, p->rec_len);
1386 p->rec_buf = new_buf;
1396 * indent-tabs-mode: nil
1398 * vim: shiftwidth=4 tabstop=8 expandtab