1 /* $Id: recgrs.c,v 1.10 2006-11-29 18:06:57 adam Exp $
2 Copyright (C) 1995-2006
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>
32 #include <idzebra/recgrs.h>
34 #define GRS_MAX_WORD 512
36 struct source_parser {
44 static int sp_lex(struct source_parser *sp)
46 while (*sp->src == ' ')
50 while (*sp->src && !strchr("<>();,-: ", *sp->src))
59 sp->lookahead = *sp->src;
66 static int sp_expr(struct source_parser *sp, data1_node *n, RecWord *wrd);
68 static int sp_range(struct source_parser *sp, data1_node *n, RecWord *wrd)
75 if (sp->lookahead != '(')
77 sp_lex(sp); /* skip ( */
80 if (!sp_expr(sp, n, wrd))
83 if (sp->lookahead != ',')
85 sp_lex(sp); /* skip , */
88 if (!sp_expr(sp, n, &tmp_w))
90 start = atoi_n(tmp_w.term_buf, tmp_w.term_len);
92 if (sp->lookahead == ',')
94 sp_lex(sp); /* skip , */
97 if (!sp_expr(sp, n, &tmp_w))
99 len = atoi_n(tmp_w.term_buf, tmp_w.term_len);
105 if (sp->lookahead != ')')
109 if (wrd->term_buf && wrd->term_len)
111 wrd->term_buf += start;
112 wrd->term_len -= start;
113 if (wrd->term_len > len)
119 static int sp_first(struct source_parser *sp, data1_node *n, RecWord *wrd)
124 if (sp->lookahead != '(')
126 sp_lex(sp); /* skip ( */
127 if (!sp_expr(sp, n, wrd))
129 while (sp->lookahead == ',')
133 sp_lex(sp); /* skip , */
135 if (!sp_expr(sp, n, &search_w))
137 for (i = 0; i<wrd->term_len; i++)
140 for (j = 0; j<search_w.term_len && i+j < wrd->term_len; j++)
141 if (wrd->term_buf[i+j] != search_w.term_buf[j])
143 if (j == search_w.term_len) /* match ? */
145 if (min_pos == -1 || i < min_pos)
151 if (sp->lookahead != ')')
155 min_pos = 0; /* the default if not found */
156 sprintf(num_str, "%d", min_pos);
157 wrd->term_buf = nmem_strdup(sp->nmem, num_str);
158 wrd->term_len = strlen(wrd->term_buf);
162 static int sp_expr(struct source_parser *sp, data1_node *n, RecWord *wrd)
164 if (sp->lookahead != 't')
166 if (sp->len == 4 && !memcmp(sp->tok, "data", sp->len))
168 if (n->which == DATA1N_data)
170 wrd->term_buf = n->u.data.data;
171 wrd->term_len = n->u.data.len;
175 else if (sp->len == 3 && !memcmp(sp->tok, "tag", sp->len))
177 if (n->which == DATA1N_tag)
179 wrd->term_buf = n->u.tag.tag;
180 wrd->term_len = strlen(n->u.tag.tag);
184 else if (sp->len == 4 && !memcmp(sp->tok, "attr", sp->len))
188 if (sp->lookahead != '(')
192 if (!sp_expr(sp, n, &tmp_w))
197 if (n->which == DATA1N_tag)
199 data1_xattr *p = n->u.tag.attributes;
200 while (p && strlen(p->name) != tmp_w.term_len &&
201 memcmp (p->name, tmp_w.term_buf, tmp_w.term_len))
205 wrd->term_buf = p->value;
206 wrd->term_len = strlen(p->value);
209 if (sp->lookahead != ')')
213 else if (sp->len == 5 && !memcmp(sp->tok, "first", sp->len))
215 return sp_first(sp, n, wrd);
217 else if (sp->len == 5 && !memcmp(sp->tok, "range", sp->len))
219 return sp_range(sp, n, wrd);
221 else if (sp->len > 0 && isdigit(*(unsigned char *)sp->tok))
224 wrd->term_len = sp->len;
225 b = nmem_malloc(sp->nmem, sp->len);
226 memcpy(b, sp->tok, sp->len);
230 else if (sp->len > 2 && sp->tok[0] == '\'' && sp->tok[sp->len-1] == '\'')
233 wrd->term_len = sp->len - 2;
234 b = nmem_malloc(sp->nmem, wrd->term_len);
235 memcpy(b, sp->tok+1, wrd->term_len);
248 static struct source_parser *source_parser_create(void)
250 struct source_parser *sp = xmalloc(sizeof(*sp));
252 sp->nmem = nmem_create();
256 static void source_parser_destroy(struct source_parser *sp)
260 nmem_destroy(sp->nmem);
264 static int sp_parse(struct source_parser *sp,
265 data1_node *n, RecWord *wrd, const char *src)
271 nmem_reset(sp->nmem);
274 return sp_expr(sp, n, wrd);
277 int d1_check_xpath_predicate(data1_node *n, struct xpath_predicate *p)
286 if (p->which == XPATH_PREDICATE_RELATION) {
287 if (p->u.relation.name[0]) {
288 if (*p->u.relation.name != '@') {
290 " Only attributes (@) are supported in xelm xpath predicates");
291 yaz_log(YLOG_WARN, "predicate %s ignored", p->u.relation.name);
294 attname = p->u.relation.name + 1;
296 /* looking for the attribute with a specified name */
297 for (attr = n->u.tag.attributes; attr; attr = attr->next) {
298 yaz_log(YLOG_DEBUG," - attribute %s <-> %s", attname, attr->name );
300 if (!strcmp(attr->name, attname)) {
301 if (p->u.relation.op[0]) {
302 if (*p->u.relation.op != '=') {
304 "Only '=' relation is supported (%s)",p->u.relation.op);
305 yaz_log(YLOG_WARN, "predicate %s ignored", p->u.relation.name);
308 yaz_log(YLOG_DEBUG," - value %s <-> %s",
309 p->u.relation.value, attr->value );
310 if (!strcmp(attr->value, p->u.relation.value)) {
315 /* attribute exists, no value specified */
320 yaz_log(YLOG_DEBUG, "return %d", res);
326 else if (p->which == XPATH_PREDICATE_BOOLEAN) {
327 if (!strcmp(p->u.boolean.op,"and")) {
328 return d1_check_xpath_predicate(n, p->u.boolean.left)
329 && d1_check_xpath_predicate(n, p->u.boolean.right);
331 else if (!strcmp(p->u.boolean.op,"or")) {
332 return (d1_check_xpath_predicate(n, p->u.boolean.left)
333 || d1_check_xpath_predicate(n, p->u.boolean.right));
335 yaz_log(YLOG_WARN, "Unknown boolean relation %s, ignored",p->u.boolean.op);
344 static int dfa_match_first(struct DFA_state **dfaar, const char *text)
346 struct DFA_state *s = dfaar[0]; /* start state */
349 const char *p = text;
352 for (c = *p++, t = s->trans, i = s->tran_no; --i >= 0; t++)
354 if (c >= t->ch[0] && c <= t->ch[1])
358 /* move to next state and return if we get a match */
366 for (t = s->trans, i = s->tran_no; --i >= 0; t++)
367 if (c >= t->ch[0] && c <= t->ch[1])
377 New function, looking for xpath "element" definitions in abs, by
378 tagpath, using a kind of ugly regxp search.The DFA was built while
379 parsing abs, so here we just go trough them and try to match
380 against the given tagpath. The first matching entry is returned.
384 Added support for enhanced xelm. Now [] predicates are considered
385 as well, when selecting indexing rules... (why the hell it's called
392 data1_termlist *xpath_termlist_by_tagpath(char *tagpath, data1_node *n)
394 data1_absyn *abs = n->root->u.root.absyn;
396 data1_xpelement *xpe = 0;
399 struct xpath_location_step *xp;
401 char *pexpr = xmalloc(strlen(tagpath)+5);
403 sprintf (pexpr, "/%s\n", tagpath);
405 for (xpe = abs->xp_elements; xpe; xpe = xpe->next)
406 xpe->match_state = -1; /* don't know if it matches yet */
408 for (xpe = abs->xp_elements; xpe; xpe = xpe->next)
411 int ok = xpe->match_state;
413 { /* don't know whether there is a match yet */
414 data1_xpelement *xpe1;
417 ok = dfa_match_first(xpe->dfa->states, pexpr);
420 /* mark this and following ones with same regexp */
421 for (xpe1 = xpe; xpe1; xpe1 = xpe1->match_next)
422 xpe1->match_state = ok;
425 assert (ok == 0 || ok == 1);
428 /* we have to check the perdicates up to the root node */
431 /* find the first tag up in the node structure */
432 for (nn = n; nn && nn->which != DATA1N_tag; nn = nn->parent)
435 /* go from inside out in the node structure, while going
436 backwards trough xpath location steps ... */
437 for (i = xpe->xpath_len - 1; i>0; i--)
439 yaz_log(YLOG_DEBUG, "Checking step %d: %s on tag %s",
440 i, xp[i].part, nn->u.tag.tag);
442 if (!d1_check_xpath_predicate(nn, xp[i].predicate))
444 yaz_log(YLOG_DEBUG, " Predicates didn't match");
449 if (nn->which == DATA1N_tag)
461 yaz_log(YLOG_DEBUG, "Got it");
462 return xpe->termlists;
469 1 start element (tag)
471 3 start attr (and attr-exact)
479 Now, if there is a matching xelm described in abs, for the
480 indexed element or the attribute, then the data is handled according
481 to those definitions...
483 modified by pop, 2002-12-13
486 /* add xpath index for an attribute */
487 static void index_xpath_attr (char *tag_path, char *name, char *value,
488 char *structure, struct recExtractCtrl *p,
491 wrd->index_name = ZEBRA_XPATH_ELM_BEGIN;
492 wrd->index_type = '0';
493 wrd->term_buf = tag_path;
494 wrd->term_len = strlen(tag_path);
498 wrd->index_name = ZEBRA_XPATH_ATTR_CDATA;
499 wrd->index_type = 'w';
500 wrd->term_buf = value;
501 wrd->term_len = strlen(value);
504 wrd->index_name = ZEBRA_XPATH_ELM_END;
505 wrd->index_type = '0';
506 wrd->term_buf = tag_path;
507 wrd->term_len = strlen(tag_path);
512 static void mk_tag_path_full(char *tag_path_full, size_t max, data1_node *n)
517 /* we have to fetch the whole path to the data tag */
518 for (nn = n; nn; nn = nn->parent)
520 if (nn->which == DATA1N_tag)
522 size_t tlen = strlen(nn->u.tag.tag);
523 if (tlen + flen > (max - 2))
525 memcpy (tag_path_full + flen, nn->u.tag.tag, tlen);
527 tag_path_full[flen++] = '/';
530 if (nn->which == DATA1N_root)
533 tag_path_full[flen] = 0;
537 static void index_xpath(struct source_parser *sp, data1_node *n,
538 struct recExtractCtrl *p,
539 int level, RecWord *wrd,
545 char tag_path_full[1024];
546 int termlist_only = 1;
549 if (!n->root->u.root.absyn
551 n->root->u.root.absyn->xpath_indexing == DATA1_XPATH_INDEXING_ENABLE)
559 wrd->term_buf = n->u.data.data;
560 wrd->term_len = n->u.data.len;
563 mk_tag_path_full(tag_path_full, sizeof(tag_path_full), n);
565 /* If we have a matching termlist... */
566 if (n->root->u.root.absyn &&
567 (tl = xpath_termlist_by_tagpath(tag_path_full, n)))
570 for (; tl; tl = tl->next)
572 /* need to copy recword because it may be changed */
574 wrd->index_type = *tl->structure;
575 memcpy (&wrd_tl, wrd, sizeof(*wrd));
577 sp_parse(sp, n, &wrd_tl, tl->source);
579 /* this is just the old fashioned attribute based index */
580 wrd_tl.index_name = tl->index_name;
581 if (p->flagShowRecords)
584 printf("%*sIdx: [%s]", (level + 1) * 4, "",
586 printf("%s %s", tl->index_name, tl->source);
587 printf (" XData:\"");
588 for (i = 0; i<wrd_tl.term_len && i < 40; i++)
589 fputc (wrd_tl.term_buf[i], stdout);
591 if (wrd_tl.term_len > 40)
593 fputc ('\n', stdout);
596 (*p->tokenAdd)(&wrd_tl);
597 if (wrd_tl.seqno > max_seqno)
598 max_seqno = wrd_tl.seqno;
601 wrd->seqno = max_seqno;
604 /* xpath indexing is done, if there was no termlist given,
605 or no ! in the termlist, and default indexing is enabled... */
606 if (!p->flagShowRecords && !xpdone && !termlist_only)
608 wrd->index_name = xpath_index;
609 wrd->index_type = 'w';
616 mk_tag_path_full(tag_path_full, sizeof(tag_path_full), n);
618 wrd->index_type = '0';
619 wrd->term_buf = tag_path_full;
620 wrd->term_len = strlen(tag_path_full);
621 wrd->index_name = xpath_index;
622 if (p->flagShowRecords)
624 printf("%*s tag=", (level + 1) * 4, "");
625 for (i = 0; i<wrd->term_len && i < 40; i++)
626 fputc (wrd->term_buf[i], stdout);
635 (*p->tokenAdd)(wrd); /* index element pag (AKA tag path) */
637 if (xpath_is_start == 1) /* only for the starting tag... */
639 #define MAX_ATTR_COUNT 50
640 data1_termlist *tll[MAX_ATTR_COUNT];
643 for (xp = n->u.tag.attributes; xp; xp = xp->next) {
645 char attr_tag_path_full[1024];
647 /* this could be cached as well */
648 sprintf (attr_tag_path_full, "@%s/%s",
649 xp->name, tag_path_full);
651 tll[i] = xpath_termlist_by_tagpath(attr_tag_path_full,n);
653 /* attribute (no value) */
654 wrd->index_type = '0';
655 wrd->index_name = ZEBRA_XPATH_ATTR_NAME;
656 wrd->term_buf = xp->name;
657 wrd->term_len = strlen(xp->name);
664 strlen(xp->name) + strlen(xp->value) < sizeof(comb)-2)
666 /* attribute value exact */
667 strcpy (comb, xp->name);
669 strcat (comb, xp->value);
671 wrd->index_name = ZEBRA_XPATH_ATTR_NAME;
672 wrd->index_type = '0';
673 wrd->term_buf = comb;
674 wrd->term_len = strlen(comb);
683 for (xp = n->u.tag.attributes; xp; xp = xp->next) {
685 char attr_tag_path_full[1024];
688 sprintf (attr_tag_path_full, "@%s/%s",
689 xp->name, tag_path_full);
693 /* If there is a termlist given (=xelm directive) */
694 for (; tl; tl = tl->next)
698 /* add xpath index for the attribute */
699 index_xpath_attr (attr_tag_path_full, xp->name,
700 xp->value, tl->structure,
704 /* index attribute value (only path/@attr) */
707 wrd->index_name = tl->index_name;
708 wrd->index_type = *tl->structure;
709 wrd->term_buf = xp->value;
710 wrd->term_len = strlen(xp->value);
716 /* if there was no termlist for the given path,
717 or the termlist didn't have a ! element, index
718 the attribute as "w" */
719 if ((!xpdone) && (!termlist_only))
721 index_xpath_attr (attr_tag_path_full, xp->name,
722 xp->value, "w", p, wrd);
731 static void index_termlist (struct source_parser *sp, data1_node *par,
733 struct recExtractCtrl *p, int level, RecWord *wrd)
735 data1_termlist *tlist = 0;
736 data1_datatype dtype = DATA1K_string;
739 * cycle up towards the root until we find a tag with an att..
740 * this has the effect of indexing locally defined tags with
741 * the attribute of their ancestor in the record.
744 while (!par->u.tag.element)
745 if (!par->parent || !(par=get_parent_tag(p->dh, par->parent)))
747 if (!par || !(tlist = par->u.tag.element->termlists))
749 if (par->u.tag.element->tag)
750 dtype = par->u.tag.element->tag->kind;
752 for (; tlist; tlist = tlist->next)
754 /* consider source */
756 assert(tlist->source);
757 sp_parse(sp, n, wrd, tlist->source);
759 if (wrd->term_buf && wrd->term_len)
761 if (p->flagShowRecords)
764 printf("%*sIdx: [%s]", (level + 1) * 4, "",
766 printf("%s %s", tlist->index_name, tlist->source);
767 printf (" XData:\"");
768 for (i = 0; i<wrd->term_len && i < 40; i++)
769 fputc (wrd->term_buf[i], stdout);
771 if (wrd->term_len > 40)
773 fputc ('\n', stdout);
777 wrd->index_type = *tlist->structure;
778 wrd->index_name = tlist->index_name;
785 static int dumpkeys_r(struct source_parser *sp,
786 data1_node *n, struct recExtractCtrl *p, int level,
789 for (; n; n = n->next)
791 if (p->flagShowRecords) /* display element description to user */
793 if (n->which == DATA1N_root)
795 printf("%*s", level * 4, "");
796 printf("Record type: '%s'\n", n->u.root.type);
798 else if (n->which == DATA1N_tag)
802 printf("%*s", level * 4, "");
803 if (!(e = n->u.tag.element))
804 printf("Local tag: '%s'\n", n->u.tag.tag);
807 printf("Elm: '%s' ", e->name);
810 data1_tag *t = e->tag;
812 printf("TagNam: '%s' ", t->names->name);
815 printf("%s[%d],", t->tagset->name, t->tagset->type);
818 if (t->which == DATA1T_numeric)
819 printf("%d)", t->value.numeric);
821 printf("'%s')", t->value.string);
828 if (n->which == DATA1N_tag)
830 index_termlist(sp, n, n, p, level, wrd);
831 /* index start tag */
832 if (n->root->u.root.absyn)
833 index_xpath(sp, n, p, level, wrd, ZEBRA_XPATH_ELM_BEGIN,
838 if (dumpkeys_r(sp, n->child, p, level + 1, wrd) < 0)
842 if (n->which == DATA1N_data)
844 data1_node *par = get_parent_tag(p->dh, n);
846 if (p->flagShowRecords)
848 printf("%*s", level * 4, "");
850 if (n->u.data.len > 256)
851 printf("'%.170s ... %.70s'\n", n->u.data.data,
852 n->u.data.data + n->u.data.len-70);
853 else if (n->u.data.len > 0)
854 printf("'%.*s'\n", n->u.data.len, n->u.data.data);
860 index_termlist(sp, par, n, p, level, wrd);
862 index_xpath(sp, n, p, level, wrd, ZEBRA_XPATH_CDATA,
866 if (n->which == DATA1N_tag)
869 index_xpath(sp, n, p, level, wrd, ZEBRA_XPATH_ELM_END,
873 if (p->flagShowRecords && n->which == DATA1N_root)
875 printf("%*s-------------\n\n", level * 4, "");
881 static int dumpkeys(data1_node *n, struct recExtractCtrl *p, RecWord *wrd)
883 struct source_parser *sp = source_parser_create();
884 int r = dumpkeys_r(sp, n, p, 0, wrd);
885 source_parser_destroy(sp);
889 int grs_extract_tree(struct recExtractCtrl *p, data1_node *n)
892 int oidtmp[OID_SIZE];
895 oe.proto = PROTO_Z3950;
896 oe.oclass = CLASS_SCHEMA;
899 oe.value = n->u.root.absyn->reference;
901 if ((oid_ent_to_oid (&oe, oidtmp)))
902 (*p->schemaAdd)(p, oidtmp);
906 /* data1_pr_tree(p->dh, n, stdout); */
908 return dumpkeys(n, p, &wrd);
911 static int grs_extract_sub(void *clientData, struct recExtractCtrl *p,
913 data1_node *(*grs_read)(struct grs_read_info *))
916 struct grs_read_info gri;
918 int oidtmp[OID_SIZE];
921 gri.stream = p->stream;
924 gri.clientData = clientData;
926 n = (*grs_read)(&gri);
928 return RECCTRL_EXTRACT_EOF;
929 oe.proto = PROTO_Z3950;
930 oe.oclass = CLASS_SCHEMA;
932 if (!n->u.root.absyn)
933 return RECCTRL_EXTRACT_ERROR;
937 oe.value = n->u.root.absyn->reference;
938 if ((oid_ent_to_oid (&oe, oidtmp)))
939 (*p->schemaAdd)(p, oidtmp);
941 data1_concat_text(p->dh, mem, n);
943 /* ensure our data1 tree is UTF-8 */
944 data1_iconv (p->dh, mem, n, "UTF-8", data1_get_encoding(p->dh, n));
947 data1_remove_idzebra_subtree (p->dh, n);
950 data1_pr_tree (p->dh, n, stdout);
954 if (dumpkeys(n, p, &wrd) < 0)
956 return RECCTRL_EXTRACT_ERROR_GENERIC;
958 return RECCTRL_EXTRACT_OK;
961 int zebra_grs_extract(void *clientData, struct recExtractCtrl *p,
962 data1_node *(*grs_read)(struct grs_read_info *))
965 NMEM mem = nmem_create ();
966 ret = grs_extract_sub(clientData, p, mem, grs_read);
972 * Return: -1: Nothing done. 0: Ok. >0: Bib-1 diagnostic.
974 static int process_comp(data1_handle dh, data1_node *n, Z_RecordComposition *c,
975 char **addinfo, ODR o)
977 data1_esetname *eset;
983 case Z_RecordComp_simple:
984 if (c->u.simple->which != Z_ElementSetNames_generic)
985 return 26; /* only generic form supported. Fix this later */
986 if (!(eset = data1_getesetbyname(dh, n->u.root.absyn,
987 c->u.simple->u.generic)))
989 yaz_log(YLOG_LOG, "Unknown esetname '%s'", c->u.simple->u.generic);
990 *addinfo = odr_strdup(o, c->u.simple->u.generic);
991 return 25; /* invalid esetname */
993 yaz_log(YLOG_DEBUG, "Esetname '%s' in simple compspec",
994 c->u.simple->u.generic);
997 case Z_RecordComp_complex:
998 if (c->u.complex->generic)
1000 /* insert check for schema */
1001 if ((p = c->u.complex->generic->elementSpec))
1005 case Z_ElementSpec_elementSetName:
1007 data1_getesetbyname(dh, n->u.root.absyn,
1008 p->u.elementSetName)))
1010 yaz_log(YLOG_DEBUG, "Unknown esetname '%s'",
1011 p->u.elementSetName);
1012 *addinfo = odr_strdup(o, p->u.elementSetName);
1013 return 25; /* invalid esetname */
1015 yaz_log(YLOG_DEBUG, "Esetname '%s' in complex compspec",
1016 p->u.elementSetName);
1019 case Z_ElementSpec_externalSpec:
1020 if (p->u.externalSpec->which == Z_External_espec1)
1022 yaz_log(YLOG_DEBUG, "Got Espec-1");
1023 espec = p->u.externalSpec-> u.espec1;
1027 yaz_log(YLOG_LOG, "Unknown external espec.");
1028 return 25; /* bad. what is proper diagnostic? */
1035 return 26; /* fix */
1039 yaz_log(YLOG_DEBUG, "Element: Espec-1 match");
1040 return data1_doespec1(dh, n, espec);
1044 yaz_log(YLOG_DEBUG, "Element: all match");
1049 /* Add Zebra info in separate namespace ...
1052 <metadata xmlns="http://www.indexdata.dk/zebra/">
1054 <localnumber>447</localnumber>
1055 <filename>records/genera.xml</filename>
1060 static void zebra_xml_metadata (struct recRetrieveCtrl *p, data1_node *top,
1063 const char *idzebra_ns[3];
1064 const char *i2 = "\n ";
1065 const char *i4 = "\n ";
1068 idzebra_ns[0] = "xmlns";
1069 idzebra_ns[1] = "http://www.indexdata.dk/zebra/";
1072 data1_mk_text (p->dh, mem, i2, top);
1074 n = data1_mk_tag (p->dh, mem, "idzebra", idzebra_ns, top);
1076 data1_mk_text (p->dh, mem, "\n", top);
1078 data1_mk_text (p->dh, mem, i4, n);
1080 data1_mk_tag_data_int (p->dh, n, "size", p->recordSize, mem);
1084 data1_mk_text (p->dh, mem, i4, n);
1085 data1_mk_tag_data_int (p->dh, n, "score", p->score, mem);
1087 data1_mk_text (p->dh, mem, i4, n);
1088 data1_mk_tag_data_zint (p->dh, n, "localnumber", p->localno, mem);
1091 data1_mk_text (p->dh, mem, i4, n);
1092 data1_mk_tag_data_text(p->dh, n, "filename", p->fname, mem);
1094 data1_mk_text (p->dh, mem, i2, n);
1097 int zebra_grs_retrieve(void *clientData, struct recRetrieveCtrl *p,
1098 data1_node *(*grs_read)(struct grs_read_info *))
1100 data1_node *node = 0, *onode = 0, *top;
1103 int res, selected = 0;
1105 struct grs_read_info gri;
1106 const char *tagname;
1108 int requested_schema = VAL_NONE;
1109 data1_marctab *marctab;
1112 mem = nmem_create();
1113 gri.stream = p->stream;
1116 gri.clientData = clientData;
1118 yaz_log(YLOG_DEBUG, "grs_retrieve");
1119 node = (*grs_read)(&gri);
1126 data1_concat_text(p->dh, mem, node);
1128 data1_remove_idzebra_subtree (p->dh, node);
1131 data1_pr_tree (p->dh, node, stdout);
1133 top = data1_get_root_tag (p->dh, node);
1135 yaz_log(YLOG_DEBUG, "grs_retrieve: size");
1136 tagname = data1_systag_lookup(node->u.root.absyn, "size", "size");
1138 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1140 dnew->u.data.what = DATA1I_text;
1141 dnew->u.data.data = dnew->lbuf;
1142 sprintf(dnew->u.data.data, "%d", p->recordSize);
1143 dnew->u.data.len = strlen(dnew->u.data.data);
1146 tagname = data1_systag_lookup(node->u.root.absyn, "rank", "rank");
1147 if (tagname && p->score >= 0 &&
1148 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1150 yaz_log(YLOG_DEBUG, "grs_retrieve: %s", tagname);
1151 dnew->u.data.what = DATA1I_num;
1152 dnew->u.data.data = dnew->lbuf;
1153 sprintf(dnew->u.data.data, "%d", p->score);
1154 dnew->u.data.len = strlen(dnew->u.data.data);
1157 tagname = data1_systag_lookup(node->u.root.absyn, "sysno",
1158 "localControlNumber");
1159 if (tagname && p->localno > 0 &&
1160 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1162 yaz_log(YLOG_DEBUG, "grs_retrieve: %s", tagname);
1163 dnew->u.data.what = DATA1I_text;
1164 dnew->u.data.data = dnew->lbuf;
1166 sprintf(dnew->u.data.data, ZINT_FORMAT, p->localno);
1167 dnew->u.data.len = strlen(dnew->u.data.data);
1170 if (p->input_format == VAL_TEXT_XML)
1171 zebra_xml_metadata (p, top, mem);
1174 data1_pr_tree (p->dh, node, stdout);
1176 if (p->comp && p->comp->which == Z_RecordComp_complex &&
1177 p->comp->u.complex->generic &&
1178 p->comp->u.complex->generic->which == Z_Schema_oid &&
1179 p->comp->u.complex->generic->schema.oid)
1181 oident *oe = oid_getentbyoid (p->comp->u.complex->generic->schema.oid);
1183 requested_schema = oe->value;
1185 /* If schema has been specified, map if possible, then check that
1186 * we got the right one
1188 if (requested_schema != VAL_NONE)
1190 yaz_log(YLOG_DEBUG, "grs_retrieve: schema mapping");
1191 for (map = node->u.root.absyn->maptabs; map; map = map->next)
1193 if (map->target_absyn_ref == requested_schema)
1196 if (!(node = data1_map_record(p->dh, onode, map, mem)))
1205 if (node->u.root.absyn &&
1206 requested_schema != node->u.root.absyn->reference)
1208 p->diagnostic = 238;
1214 * Does the requested format match a known syntax-mapping? (this reflects
1215 * the overlap of schema and formatting which is inherent in the MARC
1218 yaz_log(YLOG_DEBUG, "grs_retrieve: syntax mapping");
1219 if (node->u.root.absyn)
1220 for (map = node->u.root.absyn->maptabs; map; map = map->next)
1222 if (map->target_absyn_ref == p->input_format)
1225 if (!(node = data1_map_record(p->dh, onode, map, mem)))
1234 yaz_log(YLOG_DEBUG, "grs_retrieve: schemaIdentifier");
1235 if (node->u.root.absyn &&
1236 node->u.root.absyn->reference != VAL_NONE &&
1237 p->input_format == VAL_GRS1)
1241 int oidtmp[OID_SIZE];
1243 oe.proto = PROTO_Z3950;
1244 oe.oclass = CLASS_SCHEMA;
1245 oe.value = node->u.root.absyn->reference;
1247 if ((oid = oid_ent_to_oid (&oe, oidtmp)))
1250 data1_handle dh = p->dh;
1254 for (ii = oid; *ii >= 0; ii++)
1258 sprintf(p, "%d", *ii);
1261 if ((dnew = data1_mk_tag_data_wd(dh, top,
1262 "schemaIdentifier", mem)))
1264 dnew->u.data.what = DATA1I_oid;
1265 dnew->u.data.data = (char *) nmem_malloc(mem, p - tmp);
1266 memcpy(dnew->u.data.data, tmp, p - tmp);
1267 dnew->u.data.len = p - tmp;
1272 yaz_log(YLOG_DEBUG, "grs_retrieve: element spec");
1273 if (p->comp && (res = process_comp(p->dh, node, p->comp, &p->addinfo,
1276 p->diagnostic = res;
1280 else if (p->comp && !res)
1284 data1_pr_tree (p->dh, node, stdout);
1286 yaz_log(YLOG_DEBUG, "grs_retrieve: transfer syntax mapping");
1287 switch (p->output_format = (p->input_format != VAL_NONE ?
1288 p->input_format : VAL_SUTRS))
1292 data1_pr_tree (p->dh, node, stdout);
1294 /* default output encoding for XML is UTF-8 */
1295 data1_iconv (p->dh, mem, node,
1296 p->encoding ? p->encoding : "UTF-8",
1297 data1_get_encoding(p->dh, node));
1299 if (!(p->rec_buf = data1_nodetoidsgml(p->dh, node, selected,
1301 p->diagnostic = 238;
1304 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1305 memcpy (new_buf, p->rec_buf, p->rec_len);
1306 p->rec_buf = new_buf;
1310 data1_iconv (p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1312 if (!(p->rec_buf = data1_nodetogr(p->dh, node, selected,
1314 p->diagnostic = 238; /* not available in requested syntax */
1319 /* ensure our data1 tree is UTF-8 */
1320 data1_iconv (p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1322 if (!(p->rec_buf = data1_nodetoexplain(p->dh, node, selected,
1324 p->diagnostic = 238;
1329 /* ensure our data1 tree is UTF-8 */
1330 data1_iconv (p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1331 if (!(p->rec_buf = data1_nodetosummary(p->dh, node, selected,
1333 p->diagnostic = 238;
1339 data1_iconv (p->dh, mem, node, p->encoding,
1340 data1_get_encoding(p->dh, node));
1341 if (!(p->rec_buf = data1_nodetobuf(p->dh, node, selected,
1343 p->diagnostic = 238;
1346 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1347 memcpy (new_buf, p->rec_buf, p->rec_len);
1348 p->rec_buf = new_buf;
1353 data1_iconv (p->dh, mem, node, p->encoding,
1354 data1_get_encoding(p->dh, node));
1355 if (!(p->rec_buf = data1_nodetosoif(p->dh, node, selected,
1357 p->diagnostic = 238;
1360 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1361 memcpy (new_buf, p->rec_buf, p->rec_len);
1362 p->rec_buf = new_buf;
1366 if (!node->u.root.absyn)
1368 p->diagnostic = 238;
1371 for (marctab = node->u.root.absyn->marc; marctab;
1372 marctab = marctab->next)
1373 if (marctab->reference == p->input_format)
1377 p->diagnostic = 238;
1381 data1_iconv (p->dh, mem, node, p->encoding,
1382 data1_get_encoding(p->dh, node));
1383 if (!(p->rec_buf = data1_nodetomarc(p->dh, marctab, node,
1384 selected, &p->rec_len)))
1385 p->diagnostic = 238;
1388 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1389 memcpy (new_buf, p->rec_buf, p->rec_len);
1390 p->rec_buf = new_buf;
1400 * indent-tabs-mode: nil
1402 * vim: shiftwidth=4 tabstop=8 expandtab