1 /* $Id: recgrs.c,v 1.14 2007-01-22 18:15:03 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>
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 if (!strcmp(attr->name, attname)) {
299 if (p->u.relation.op[0]) {
300 if (*p->u.relation.op != '=') {
302 "Only '=' relation is supported (%s)",p->u.relation.op);
303 yaz_log(YLOG_WARN, "predicate %s ignored", p->u.relation.name);
306 if (!strcmp(attr->value, p->u.relation.value)) {
311 /* attribute exists, no value specified */
321 else if (p->which == XPATH_PREDICATE_BOOLEAN) {
322 if (!strcmp(p->u.boolean.op,"and")) {
323 return d1_check_xpath_predicate(n, p->u.boolean.left)
324 && d1_check_xpath_predicate(n, p->u.boolean.right);
326 else if (!strcmp(p->u.boolean.op,"or")) {
327 return (d1_check_xpath_predicate(n, p->u.boolean.left)
328 || d1_check_xpath_predicate(n, p->u.boolean.right));
330 yaz_log(YLOG_WARN, "Unknown boolean relation %s, ignored",p->u.boolean.op);
339 static int dfa_match_first(struct DFA_state **dfaar, const char *text)
341 struct DFA_state *s = dfaar[0]; /* start state */
344 const char *p = text;
347 for (c = *p++, t = s->trans, i = s->tran_no; --i >= 0; t++)
349 if (c >= t->ch[0] && c <= t->ch[1])
353 /* move to next state and return if we get a match */
361 for (t = s->trans, i = s->tran_no; --i >= 0; t++)
362 if (c >= t->ch[0] && c <= t->ch[1])
372 New function, looking for xpath "element" definitions in abs, by
373 tagpath, using a kind of ugly regxp search.The DFA was built while
374 parsing abs, so here we just go trough them and try to match
375 against the given tagpath. The first matching entry is returned.
379 Added support for enhanced xelm. Now [] predicates are considered
380 as well, when selecting indexing rules... (why the hell it's called
387 data1_termlist *xpath_termlist_by_tagpath(char *tagpath, data1_node *n)
389 data1_absyn *abs = n->root->u.root.absyn;
391 data1_xpelement *xpe = 0;
394 struct xpath_location_step *xp;
396 char *pexpr = xmalloc(strlen(tagpath)+5);
398 sprintf (pexpr, "/%s\n", tagpath);
400 for (xpe = abs->xp_elements; xpe; xpe = xpe->next)
401 xpe->match_state = -1; /* don't know if it matches yet */
403 for (xpe = abs->xp_elements; xpe; xpe = xpe->next)
406 int ok = xpe->match_state;
408 { /* don't know whether there is a match yet */
409 data1_xpelement *xpe1;
412 ok = dfa_match_first(xpe->dfa->states, pexpr);
415 /* mark this and following ones with same regexp */
416 for (xpe1 = xpe; xpe1; xpe1 = xpe1->match_next)
417 xpe1->match_state = ok;
420 assert (ok == 0 || ok == 1);
423 /* we have to check the perdicates up to the root node */
426 /* find the first tag up in the node structure */
427 for (nn = n; nn && nn->which != DATA1N_tag; nn = nn->parent)
430 /* go from inside out in the node structure, while going
431 backwards trough xpath location steps ... */
432 for (i = xpe->xpath_len - 1; i>0; i--)
434 if (!d1_check_xpath_predicate(nn, xp[i].predicate))
440 if (nn->which == DATA1N_tag)
452 yaz_log(YLOG_DEBUG, "Got it");
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;
541 if (!n->root->u.root.absyn
543 n->root->u.root.absyn->xpath_indexing == DATA1_XPATH_INDEXING_ENABLE)
552 wrd->term_buf = n->u.data.data;
553 wrd->term_len = n->u.data.len;
556 mk_tag_path_full(tag_path_full, sizeof(tag_path_full), n);
558 /* If we have a matching termlist... */
559 if (n->root->u.root.absyn &&
560 (tl = xpath_termlist_by_tagpath(tag_path_full, n)))
563 for (; tl; tl = tl->next)
565 /* need to copy recword because it may be changed */
567 wrd->index_type = *tl->structure;
568 memcpy (&wrd_tl, wrd, sizeof(*wrd));
570 sp_parse(sp, n, &wrd_tl, tl->source);
572 /* this is just the old fashioned attribute based index */
573 wrd_tl.index_name = tl->index_name;
574 if (p->flagShowRecords)
577 printf("%*sIdx: [%s]", (level + 1) * 4, "",
579 printf("%s %s", tl->index_name, tl->source);
580 printf (" XData:\"");
581 for (i = 0; i<wrd_tl.term_len && i < 40; i++)
582 fputc (wrd_tl.term_buf[i], stdout);
584 if (wrd_tl.term_len > 40)
586 fputc ('\n', stdout);
590 (*p->tokenAdd)(&wrd_tl);
592 if (wrd_tl.seqno > max_seqno)
593 max_seqno = wrd_tl.seqno;
596 wrd->seqno = max_seqno;
599 /* xpath indexing is done, if there was no termlist given,
600 or no ! in the termlist, and default indexing is enabled... */
601 if (!p->flagShowRecords && !xpdone && !termlist_only)
603 wrd->index_name = xpath_index;
604 wrd->index_type = 'w';
611 mk_tag_path_full(tag_path_full, sizeof(tag_path_full), n);
613 wrd->index_type = '0';
614 wrd->term_buf = tag_path_full;
615 wrd->term_len = strlen(tag_path_full);
616 wrd->index_name = xpath_index;
617 if (p->flagShowRecords)
619 printf("%*s tag=", (level + 1) * 4, "");
620 for (i = 0; i<wrd->term_len && i < 40; i++)
621 fputc (wrd->term_buf[i], stdout);
630 (*p->tokenAdd)(wrd); /* index element pag (AKA tag path) */
632 if (xpath_is_start == 1) /* only for the starting tag... */
634 #define MAX_ATTR_COUNT 50
635 data1_termlist *tll[MAX_ATTR_COUNT];
638 for (xp = n->u.tag.attributes; xp; xp = xp->next) {
640 char attr_tag_path_full[1024];
642 /* this could be cached as well */
643 sprintf (attr_tag_path_full, "@%s/%s",
644 xp->name, tag_path_full);
646 tll[i] = xpath_termlist_by_tagpath(attr_tag_path_full,n);
648 /* attribute (no value) */
649 wrd->index_type = '0';
650 wrd->index_name = ZEBRA_XPATH_ATTR_NAME;
651 wrd->term_buf = xp->name;
652 wrd->term_len = strlen(xp->name);
659 strlen(xp->name) + strlen(xp->value) < sizeof(comb)-2)
661 /* attribute value exact */
662 strcpy (comb, xp->name);
664 strcat (comb, xp->value);
666 wrd->index_name = ZEBRA_XPATH_ATTR_NAME;
667 wrd->index_type = '0';
668 wrd->term_buf = comb;
669 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);
688 /* If there is a termlist given (=xelm directive) */
689 for (; tl; tl = tl->next)
693 /* add xpath index for the attribute */
694 index_xpath_attr (attr_tag_path_full, xp->name,
695 xp->value, tl->structure,
699 /* index attribute value (only path/@attr) */
702 wrd->index_name = tl->index_name;
703 wrd->index_type = *tl->structure;
704 wrd->term_buf = xp->value;
705 wrd->term_len = strlen(xp->value);
711 /* if there was no termlist for the given path,
712 or the termlist didn't have a ! element, index
713 the attribute as "w" */
714 if ((!xpdone) && (!termlist_only))
716 index_xpath_attr (attr_tag_path_full, xp->name,
717 xp->value, "w", p, wrd);
726 static void index_termlist (struct source_parser *sp, data1_node *par,
728 struct recExtractCtrl *p, int level, RecWord *wrd)
730 data1_termlist *tlist = 0;
731 data1_datatype dtype = DATA1K_string;
734 * cycle up towards the root until we find a tag with an att..
735 * this has the effect of indexing locally defined tags with
736 * the attribute of their ancestor in the record.
739 while (!par->u.tag.element)
740 if (!par->parent || !(par=get_parent_tag(p->dh, par->parent)))
742 if (!par || !(tlist = par->u.tag.element->termlists))
744 if (par->u.tag.element->tag)
745 dtype = par->u.tag.element->tag->kind;
747 for (; tlist; tlist = tlist->next)
749 /* consider source */
751 assert(tlist->source);
752 sp_parse(sp, n, wrd, tlist->source);
754 if (wrd->term_buf && wrd->term_len)
756 if (p->flagShowRecords)
759 printf("%*sIdx: [%s]", (level + 1) * 4, "",
761 printf("%s %s", tlist->index_name, tlist->source);
762 printf (" XData:\"");
763 for (i = 0; i<wrd->term_len && i < 40; i++)
764 fputc (wrd->term_buf[i], stdout);
766 if (wrd->term_len > 40)
768 fputc ('\n', stdout);
772 wrd->index_type = *tlist->structure;
773 wrd->index_name = tlist->index_name;
780 static int dumpkeys_r(struct source_parser *sp,
781 data1_node *n, struct recExtractCtrl *p, int level,
784 for (; n; n = n->next)
786 if (p->flagShowRecords) /* display element description to user */
788 if (n->which == DATA1N_root)
790 printf("%*s", level * 4, "");
791 printf("Record type: '%s'\n", n->u.root.type);
793 else if (n->which == DATA1N_tag)
797 printf("%*s", level * 4, "");
798 if (!(e = n->u.tag.element))
799 printf("Local tag: '%s'\n", n->u.tag.tag);
802 printf("Elm: '%s' ", e->name);
805 data1_tag *t = e->tag;
807 printf("TagNam: '%s' ", t->names->name);
810 printf("%s[%d],", t->tagset->name, t->tagset->type);
813 if (t->which == DATA1T_numeric)
814 printf("%d)", t->value.numeric);
816 printf("'%s')", t->value.string);
823 if (n->which == DATA1N_tag)
825 index_termlist(sp, n, n, p, level, wrd);
826 /* index start tag */
827 if (n->root->u.root.absyn)
828 index_xpath(sp, n, p, level, wrd, ZEBRA_XPATH_ELM_BEGIN,
833 if (dumpkeys_r(sp, n->child, p, level + 1, wrd) < 0)
837 if (n->which == DATA1N_data)
839 data1_node *par = get_parent_tag(p->dh, n);
841 if (p->flagShowRecords)
843 printf("%*s", level * 4, "");
845 if (n->u.data.len > 256)
846 printf("'%.170s ... %.70s'\n", n->u.data.data,
847 n->u.data.data + n->u.data.len-70);
848 else if (n->u.data.len > 0)
849 printf("'%.*s'\n", n->u.data.len, n->u.data.data);
855 index_termlist(sp, par, n, p, level, wrd);
857 index_xpath(sp, n, p, level, wrd, ZEBRA_XPATH_CDATA,
861 if (n->which == DATA1N_tag)
864 index_xpath(sp, n, p, level, wrd, ZEBRA_XPATH_ELM_END,
868 if (p->flagShowRecords && n->which == DATA1N_root)
870 printf("%*s-------------\n\n", level * 4, "");
876 static int dumpkeys(data1_node *n, struct recExtractCtrl *p, RecWord *wrd)
878 struct source_parser *sp = source_parser_create();
879 int r = dumpkeys_r(sp, n, p, 0, wrd);
880 source_parser_destroy(sp);
884 int grs_extract_tree(struct recExtractCtrl *p, data1_node *n)
887 int oidtmp[OID_SIZE];
890 oe.proto = PROTO_Z3950;
891 oe.oclass = CLASS_SCHEMA;
894 oe.value = n->u.root.absyn->reference;
896 if ((oid_ent_to_oid (&oe, oidtmp)))
897 (*p->schemaAdd)(p, oidtmp);
901 /* data1_pr_tree(p->dh, n, stdout); */
903 return dumpkeys(n, p, &wrd);
906 static int grs_extract_sub(void *clientData, struct recExtractCtrl *p,
908 data1_node *(*grs_read)(struct grs_read_info *))
911 struct grs_read_info gri;
913 int oidtmp[OID_SIZE];
916 gri.stream = p->stream;
919 gri.clientData = clientData;
921 n = (*grs_read)(&gri);
923 return RECCTRL_EXTRACT_EOF;
924 oe.proto = PROTO_Z3950;
925 oe.oclass = CLASS_SCHEMA;
927 if (!n->u.root.absyn)
928 return RECCTRL_EXTRACT_ERROR;
932 oe.value = n->u.root.absyn->reference;
933 if ((oid_ent_to_oid (&oe, oidtmp)))
934 (*p->schemaAdd)(p, oidtmp);
936 data1_concat_text(p->dh, mem, n);
938 /* ensure our data1 tree is UTF-8 */
939 data1_iconv (p->dh, mem, n, "UTF-8", data1_get_encoding(p->dh, n));
942 data1_remove_idzebra_subtree (p->dh, n);
945 data1_pr_tree (p->dh, n, stdout);
949 if (dumpkeys(n, p, &wrd) < 0)
951 return RECCTRL_EXTRACT_ERROR_GENERIC;
953 return RECCTRL_EXTRACT_OK;
956 int zebra_grs_extract(void *clientData, struct recExtractCtrl *p,
957 data1_node *(*grs_read)(struct grs_read_info *))
960 NMEM mem = nmem_create ();
961 ret = grs_extract_sub(clientData, p, mem, grs_read);
967 * Return: -1: Nothing done. 0: Ok. >0: Bib-1 diagnostic.
969 static int process_comp(data1_handle dh, data1_node *n, Z_RecordComposition *c,
970 char **addinfo, ODR o)
972 data1_esetname *eset;
978 case Z_RecordComp_simple:
979 if (c->u.simple->which != Z_ElementSetNames_generic)
980 return 26; /* only generic form supported. Fix this later */
981 if (!(eset = data1_getesetbyname(dh, n->u.root.absyn,
982 c->u.simple->u.generic)))
984 yaz_log(YLOG_LOG, "Unknown esetname '%s'", c->u.simple->u.generic);
985 *addinfo = odr_strdup(o, c->u.simple->u.generic);
986 return 25; /* invalid esetname */
988 yaz_log(YLOG_DEBUG, "Esetname '%s' in simple compspec",
989 c->u.simple->u.generic);
992 case Z_RecordComp_complex:
993 if (c->u.complex->generic)
995 /* insert check for schema */
996 if ((p = c->u.complex->generic->elementSpec))
1000 case Z_ElementSpec_elementSetName:
1002 data1_getesetbyname(dh, n->u.root.absyn,
1003 p->u.elementSetName)))
1005 yaz_log(YLOG_DEBUG, "Unknown esetname '%s'",
1006 p->u.elementSetName);
1007 *addinfo = odr_strdup(o, p->u.elementSetName);
1008 return 25; /* invalid esetname */
1010 yaz_log(YLOG_DEBUG, "Esetname '%s' in complex compspec",
1011 p->u.elementSetName);
1014 case Z_ElementSpec_externalSpec:
1015 if (p->u.externalSpec->which == Z_External_espec1)
1017 yaz_log(YLOG_DEBUG, "Got Espec-1");
1018 espec = p->u.externalSpec-> u.espec1;
1022 yaz_log(YLOG_LOG, "Unknown external espec.");
1023 return 25; /* bad. what is proper diagnostic? */
1030 return 26; /* fix */
1034 yaz_log(YLOG_DEBUG, "Element: Espec-1 match");
1035 return data1_doespec1(dh, n, espec);
1039 yaz_log(YLOG_DEBUG, "Element: all match");
1044 /* Add Zebra info in separate namespace ...
1047 <metadata xmlns="http://www.indexdata.dk/zebra/">
1049 <localnumber>447</localnumber>
1050 <filename>records/genera.xml</filename>
1055 static void zebra_xml_metadata (struct recRetrieveCtrl *p, data1_node *top,
1058 const char *idzebra_ns[3];
1059 const char *i2 = "\n ";
1060 const char *i4 = "\n ";
1063 idzebra_ns[0] = "xmlns";
1064 idzebra_ns[1] = "http://www.indexdata.dk/zebra/";
1067 data1_mk_text (p->dh, mem, i2, top);
1069 n = data1_mk_tag (p->dh, mem, "idzebra", idzebra_ns, top);
1071 data1_mk_text (p->dh, mem, "\n", top);
1073 data1_mk_text (p->dh, mem, i4, n);
1075 data1_mk_tag_data_int (p->dh, n, "size", p->recordSize, mem);
1079 data1_mk_text (p->dh, mem, i4, n);
1080 data1_mk_tag_data_int (p->dh, n, "score", p->score, mem);
1082 data1_mk_text (p->dh, mem, i4, n);
1083 data1_mk_tag_data_zint (p->dh, n, "localnumber", p->localno, mem);
1086 data1_mk_text (p->dh, mem, i4, n);
1087 data1_mk_tag_data_text(p->dh, n, "filename", p->fname, mem);
1089 data1_mk_text (p->dh, mem, i2, n);
1092 int zebra_grs_retrieve(void *clientData, struct recRetrieveCtrl *p,
1093 data1_node *(*grs_read)(struct grs_read_info *))
1095 data1_node *node = 0, *onode = 0, *top;
1098 int res, selected = 0;
1100 struct grs_read_info gri;
1101 const char *tagname;
1103 int requested_schema = VAL_NONE;
1104 data1_marctab *marctab;
1107 mem = nmem_create();
1108 gri.stream = p->stream;
1111 gri.clientData = clientData;
1113 yaz_log(YLOG_DEBUG, "grs_retrieve");
1114 node = (*grs_read)(&gri);
1121 data1_concat_text(p->dh, mem, node);
1123 data1_remove_idzebra_subtree (p->dh, node);
1126 data1_pr_tree (p->dh, node, stdout);
1128 top = data1_get_root_tag (p->dh, node);
1130 yaz_log(YLOG_DEBUG, "grs_retrieve: size");
1131 tagname = data1_systag_lookup(node->u.root.absyn, "size", "size");
1133 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1135 dnew->u.data.what = DATA1I_text;
1136 dnew->u.data.data = dnew->lbuf;
1137 sprintf(dnew->u.data.data, "%d", p->recordSize);
1138 dnew->u.data.len = strlen(dnew->u.data.data);
1141 tagname = data1_systag_lookup(node->u.root.absyn, "rank", "rank");
1142 if (tagname && p->score >= 0 &&
1143 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1145 yaz_log(YLOG_DEBUG, "grs_retrieve: %s", tagname);
1146 dnew->u.data.what = DATA1I_num;
1147 dnew->u.data.data = dnew->lbuf;
1148 sprintf(dnew->u.data.data, "%d", p->score);
1149 dnew->u.data.len = strlen(dnew->u.data.data);
1152 tagname = data1_systag_lookup(node->u.root.absyn, "sysno",
1153 "localControlNumber");
1154 if (tagname && p->localno > 0 &&
1155 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1157 yaz_log(YLOG_DEBUG, "grs_retrieve: %s", tagname);
1158 dnew->u.data.what = DATA1I_text;
1159 dnew->u.data.data = dnew->lbuf;
1161 sprintf(dnew->u.data.data, ZINT_FORMAT, p->localno);
1162 dnew->u.data.len = strlen(dnew->u.data.data);
1165 if (p->input_format == VAL_TEXT_XML)
1166 zebra_xml_metadata (p, top, mem);
1169 data1_pr_tree (p->dh, node, stdout);
1171 if (p->comp && p->comp->which == Z_RecordComp_complex &&
1172 p->comp->u.complex->generic &&
1173 p->comp->u.complex->generic->which == Z_Schema_oid &&
1174 p->comp->u.complex->generic->schema.oid)
1176 oident *oe = oid_getentbyoid (p->comp->u.complex->generic->schema.oid);
1178 requested_schema = oe->value;
1180 /* If schema has been specified, map if possible, then check that
1181 * we got the right one
1183 if (requested_schema != VAL_NONE)
1185 yaz_log(YLOG_DEBUG, "grs_retrieve: schema mapping");
1186 for (map = node->u.root.absyn->maptabs; map; map = map->next)
1188 if (map->target_absyn_ref == requested_schema)
1191 if (!(node = data1_map_record(p->dh, onode, map, mem)))
1200 if (node->u.root.absyn &&
1201 requested_schema != node->u.root.absyn->reference)
1203 p->diagnostic = 238;
1209 * Does the requested format match a known syntax-mapping? (this reflects
1210 * the overlap of schema and formatting which is inherent in the MARC
1213 yaz_log(YLOG_DEBUG, "grs_retrieve: syntax mapping");
1214 if (node->u.root.absyn)
1215 for (map = node->u.root.absyn->maptabs; map; map = map->next)
1217 if (map->target_absyn_ref == p->input_format)
1220 if (!(node = data1_map_record(p->dh, onode, map, mem)))
1229 yaz_log(YLOG_DEBUG, "grs_retrieve: schemaIdentifier");
1230 if (node->u.root.absyn &&
1231 node->u.root.absyn->reference != VAL_NONE &&
1232 p->input_format == VAL_GRS1)
1236 int oidtmp[OID_SIZE];
1238 oe.proto = PROTO_Z3950;
1239 oe.oclass = CLASS_SCHEMA;
1240 oe.value = node->u.root.absyn->reference;
1242 if ((oid = oid_ent_to_oid (&oe, oidtmp)))
1245 data1_handle dh = p->dh;
1249 for (ii = oid; *ii >= 0; ii++)
1253 sprintf(p, "%d", *ii);
1256 if ((dnew = data1_mk_tag_data_wd(dh, top,
1257 "schemaIdentifier", mem)))
1259 dnew->u.data.what = DATA1I_oid;
1260 dnew->u.data.data = (char *) nmem_malloc(mem, p - tmp);
1261 memcpy(dnew->u.data.data, tmp, p - tmp);
1262 dnew->u.data.len = p - tmp;
1267 yaz_log(YLOG_DEBUG, "grs_retrieve: element spec");
1268 if (p->comp && (res = process_comp(p->dh, node, p->comp, &p->addinfo,
1271 p->diagnostic = res;
1275 else if (p->comp && !res)
1279 data1_pr_tree (p->dh, node, stdout);
1281 yaz_log(YLOG_DEBUG, "grs_retrieve: transfer syntax mapping");
1282 switch (p->output_format = (p->input_format != VAL_NONE ?
1283 p->input_format : VAL_SUTRS))
1287 data1_pr_tree (p->dh, node, stdout);
1289 /* default output encoding for XML is UTF-8 */
1290 data1_iconv (p->dh, mem, node,
1291 p->encoding ? p->encoding : "UTF-8",
1292 data1_get_encoding(p->dh, node));
1294 if (!(p->rec_buf = data1_nodetoidsgml(p->dh, node, selected,
1296 p->diagnostic = 238;
1299 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1300 memcpy (new_buf, p->rec_buf, p->rec_len);
1301 p->rec_buf = new_buf;
1305 data1_iconv (p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1307 if (!(p->rec_buf = data1_nodetogr(p->dh, node, selected,
1309 p->diagnostic = 238; /* not available in requested syntax */
1314 /* ensure our data1 tree is UTF-8 */
1315 data1_iconv (p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1317 if (!(p->rec_buf = data1_nodetoexplain(p->dh, node, selected,
1319 p->diagnostic = 238;
1324 /* ensure our data1 tree is UTF-8 */
1325 data1_iconv (p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1326 if (!(p->rec_buf = data1_nodetosummary(p->dh, node, selected,
1328 p->diagnostic = 238;
1334 data1_iconv (p->dh, mem, node, p->encoding,
1335 data1_get_encoding(p->dh, node));
1336 if (!(p->rec_buf = data1_nodetobuf(p->dh, node, selected,
1338 p->diagnostic = 238;
1341 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1342 memcpy (new_buf, p->rec_buf, p->rec_len);
1343 p->rec_buf = new_buf;
1348 data1_iconv (p->dh, mem, node, p->encoding,
1349 data1_get_encoding(p->dh, node));
1350 if (!(p->rec_buf = data1_nodetosoif(p->dh, node, selected,
1352 p->diagnostic = 238;
1355 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1356 memcpy (new_buf, p->rec_buf, p->rec_len);
1357 p->rec_buf = new_buf;
1361 if (!node->u.root.absyn)
1363 p->diagnostic = 238;
1366 for (marctab = node->u.root.absyn->marc; marctab;
1367 marctab = marctab->next)
1368 if (marctab->reference == p->input_format)
1372 p->diagnostic = 238;
1376 data1_iconv (p->dh, mem, node, p->encoding,
1377 data1_get_encoding(p->dh, node));
1378 if (!(p->rec_buf = data1_nodetomarc(p->dh, marctab, node,
1379 selected, &p->rec_len)))
1380 p->diagnostic = 238;
1383 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1384 memcpy (new_buf, p->rec_buf, p->rec_len);
1385 p->rec_buf = new_buf;
1395 * indent-tabs-mode: nil
1397 * vim: shiftwidth=4 tabstop=8 expandtab