1 /* This file is part of the Zebra server.
2 Copyright (C) 1994-2011 Index Data
4 Zebra is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
9 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 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 != ')')
112 if (start >= wrd->term_len)
116 wrd->term_len -= start;
117 wrd->term_buf += start;
119 if (wrd->term_len > len)
126 static int sp_first(struct source_parser *sp, data1_node *n, RecWord *wrd)
131 if (sp->lookahead != '(')
133 sp_lex(sp); /* skip ( */
134 if (!sp_expr(sp, n, wrd))
136 while (sp->lookahead == ',')
140 sp_lex(sp); /* skip , */
142 if (!sp_expr(sp, n, &search_w))
144 for (i = 0; i<wrd->term_len; i++)
147 for (j = 0; j<search_w.term_len && i+j < wrd->term_len; j++)
148 if (wrd->term_buf[i+j] != search_w.term_buf[j])
150 if (j == search_w.term_len) /* match ? */
152 if (min_pos == -1 || i < min_pos)
158 if (sp->lookahead != ')')
162 min_pos = 0; /* the default if not found */
163 sprintf(num_str, "%d", min_pos);
164 wrd->term_buf = nmem_strdup(sp->nmem, num_str);
165 wrd->term_len = strlen(wrd->term_buf);
169 static int sp_expr(struct source_parser *sp, data1_node *n, RecWord *wrd)
171 if (sp->lookahead != 't')
173 if (sp->len == 4 && !memcmp(sp->tok, "data", sp->len))
175 if (n->which == DATA1N_data)
177 wrd->term_buf = n->u.data.data;
178 wrd->term_len = n->u.data.len;
182 else if (sp->len == 3 && !memcmp(sp->tok, "tag", sp->len))
184 if (n->which == DATA1N_tag)
186 wrd->term_buf = n->u.tag.tag;
187 wrd->term_len = strlen(n->u.tag.tag);
191 else if (sp->len == 4 && !memcmp(sp->tok, "attr", sp->len))
195 if (sp->lookahead != '(')
199 if (!sp_expr(sp, n, &tmp_w))
204 if (n->which == DATA1N_tag)
206 data1_xattr *p = n->u.tag.attributes;
207 while (p && strlen(p->name) != tmp_w.term_len &&
208 memcmp (p->name, tmp_w.term_buf, tmp_w.term_len))
212 wrd->term_buf = p->value;
213 wrd->term_len = strlen(p->value);
216 if (sp->lookahead != ')')
220 else if (sp->len == 5 && !memcmp(sp->tok, "first", sp->len))
222 return sp_first(sp, n, wrd);
224 else if (sp->len == 5 && !memcmp(sp->tok, "range", sp->len))
226 return sp_range(sp, n, wrd);
228 else if (sp->len > 0 && isdigit(*(unsigned char *)sp->tok))
231 wrd->term_len = sp->len;
232 b = nmem_malloc(sp->nmem, sp->len);
233 memcpy(b, sp->tok, sp->len);
237 else if (sp->len > 2 && sp->tok[0] == '\'' && sp->tok[sp->len-1] == '\'')
240 wrd->term_len = sp->len - 2;
241 b = nmem_malloc(sp->nmem, wrd->term_len);
242 memcpy(b, sp->tok+1, wrd->term_len);
255 static struct source_parser *source_parser_create(void)
257 struct source_parser *sp = xmalloc(sizeof(*sp));
259 sp->nmem = nmem_create();
263 static void source_parser_destroy(struct source_parser *sp)
267 nmem_destroy(sp->nmem);
271 static int sp_parse(struct source_parser *sp,
272 data1_node *n, RecWord *wrd, const char *src)
278 nmem_reset(sp->nmem);
281 return sp_expr(sp, n, wrd);
284 int d1_check_xpath_predicate(data1_node *n, struct xpath_predicate *p)
293 if (p->which == XPATH_PREDICATE_RELATION) {
294 if (p->u.relation.name[0]) {
295 if (*p->u.relation.name != '@') {
297 " Only attributes (@) are supported in xelm xpath predicates");
298 yaz_log(YLOG_WARN, "predicate %s ignored", p->u.relation.name);
301 attname = p->u.relation.name + 1;
303 /* looking for the attribute with a specified name */
304 for (attr = n->u.tag.attributes; attr; attr = attr->next) {
305 if (!strcmp(attr->name, attname)) {
306 if (p->u.relation.op[0]) {
307 if (*p->u.relation.op != '=') {
309 "Only '=' relation is supported (%s)",p->u.relation.op);
310 yaz_log(YLOG_WARN, "predicate %s ignored", p->u.relation.name);
313 if (!strcmp(attr->value, p->u.relation.value)) {
318 /* attribute exists, no value specified */
328 else if (p->which == XPATH_PREDICATE_BOOLEAN) {
329 if (!strcmp(p->u.boolean.op,"and")) {
330 return d1_check_xpath_predicate(n, p->u.boolean.left)
331 && d1_check_xpath_predicate(n, p->u.boolean.right);
333 else if (!strcmp(p->u.boolean.op,"or")) {
334 return (d1_check_xpath_predicate(n, p->u.boolean.left)
335 || d1_check_xpath_predicate(n, p->u.boolean.right));
337 yaz_log(YLOG_WARN, "Unknown boolean relation %s, ignored",p->u.boolean.op);
346 static int dfa_match_first(struct DFA_state **dfaar, const char *text)
348 struct DFA_state *s = dfaar[0]; /* start state */
351 const char *p = text;
354 for (c = *p++, t = s->trans, i = s->tran_no; --i >= 0; t++)
356 if (c >= t->ch[0] && c <= t->ch[1])
360 /* move to next state and return if we get a match */
368 for (t = s->trans, i = s->tran_no; --i >= 0; t++)
369 if (c >= t->ch[0] && c <= t->ch[1])
379 New function, looking for xpath "element" definitions in abs, by
380 tagpath, using a kind of ugly regxp search.The DFA was built while
381 parsing abs, so here we just go trough them and try to match
382 against the given tagpath. The first matching entry is returned.
386 Added support for enhanced xelm. Now [] predicates are considered
387 as well, when selecting indexing rules... (why the hell it's called
394 data1_termlist *xpath_termlist_by_tagpath(char *tagpath, data1_node *n)
396 data1_absyn *abs = n->root->u.root.absyn;
398 data1_xpelement *xpe = 0;
401 struct xpath_location_step *xp;
403 char *pexpr = xmalloc(strlen(tagpath)+5);
405 sprintf(pexpr, "/%s\n", tagpath);
407 for (xpe = abs->xp_elements; xpe; xpe = xpe->next)
408 xpe->match_state = -1; /* don't know if it matches yet */
410 for (xpe = abs->xp_elements; xpe; xpe = xpe->next)
413 int ok = xpe->match_state;
415 { /* don't know whether there is a match yet */
416 data1_xpelement *xpe1;
419 ok = dfa_match_first(xpe->dfa->states, pexpr);
422 /* mark this and following ones with same regexp */
423 for (xpe1 = xpe; xpe1; xpe1 = xpe1->match_next)
424 xpe1->match_state = ok;
427 assert(ok == 0 || ok == 1);
430 /* we have to check the perdicates up to the root node */
433 /* find the first tag up in the node structure */
434 for (nn = n; nn && nn->which != DATA1N_tag; nn = nn->parent)
437 /* go from inside out in the node structure, while going
438 backwards trough xpath location steps ... */
439 for (i = xpe->xpath_len - 1; i>0; i--)
441 if (!d1_check_xpath_predicate(nn, xp[i].predicate))
447 if (nn->which == DATA1N_tag)
459 return xpe->termlists;
466 1 start element (tag)
468 3 start attr (and attr-exact)
476 Now, if there is a matching xelm described in abs, for the
477 indexed element or the attribute, then the data is handled according
478 to those definitions...
480 modified by pop, 2002-12-13
483 /* add xpath index for an attribute */
484 static void index_xpath_attr(char *tag_path, char *name, char *value,
485 char *structure, struct recExtractCtrl *p,
488 wrd->index_name = ZEBRA_XPATH_ELM_BEGIN;
489 wrd->index_type = "0";
490 wrd->term_buf = tag_path;
491 wrd->term_len = strlen(tag_path);
495 wrd->index_name = ZEBRA_XPATH_ATTR_CDATA;
496 wrd->index_type = "w";
497 wrd->term_buf = value;
498 wrd->term_len = strlen(value);
501 wrd->index_name = ZEBRA_XPATH_ELM_END;
502 wrd->index_type = "0";
503 wrd->term_buf = tag_path;
504 wrd->term_len = strlen(tag_path);
509 static void mk_tag_path_full(char *tag_path_full, size_t max, data1_node *n)
514 /* we have to fetch the whole path to the data tag */
515 for (nn = n; nn; nn = nn->parent)
517 if (nn->which == DATA1N_tag)
519 size_t tlen = strlen(nn->u.tag.tag);
520 if (tlen + flen > (max - 2))
522 memcpy(tag_path_full + flen, nn->u.tag.tag, tlen);
524 tag_path_full[flen++] = '/';
527 if (nn->which == DATA1N_root)
530 tag_path_full[flen] = 0;
534 static void index_xpath(struct source_parser *sp, data1_node *n,
535 struct recExtractCtrl *p,
536 int level, RecWord *wrd,
542 char tag_path_full[1024];
543 int termlist_only = 1;
546 if (!n->root->u.root.absyn
548 n->root->u.root.absyn->xpath_indexing == DATA1_XPATH_INDEXING_ENABLE)
557 wrd->term_buf = n->u.data.data;
558 wrd->term_len = n->u.data.len;
560 mk_tag_path_full(tag_path_full, sizeof(tag_path_full), n);
562 /* If we have a matching termlist... */
563 if (n->root->u.root.absyn &&
564 (tl = xpath_termlist_by_tagpath(tag_path_full, n)))
567 for (; tl; tl = tl->next)
569 /* need to copy recword because it may be changed */
571 wrd->index_type = tl->structure;
572 memcpy(&wrd_tl, wrd, sizeof(*wrd));
574 sp_parse(sp, n, &wrd_tl, tl->source);
576 /* this is just the old fashioned attribute based index */
577 wrd_tl.index_name = tl->index_name;
578 if (p->flagShowRecords)
581 printf("%*sIdx: [%s]", (level + 1) * 4, "",
583 printf("%s %s", tl->index_name, tl->source);
585 for (i = 0; i<wrd_tl.term_len && i < 40; i++)
586 fputc(wrd_tl.term_buf[i], stdout);
588 if (wrd_tl.term_len > 40)
594 (*p->tokenAdd)(&wrd_tl);
596 if (wrd_tl.seqno > max_seqno)
597 max_seqno = wrd_tl.seqno;
600 wrd->seqno = max_seqno;
603 /* xpath indexing is done, if there was no termlist given,
604 or no ! in the termlist, and default indexing is enabled... */
605 if (!p->flagShowRecords && !termlist_only)
607 wrd->index_name = xpath_index;
608 wrd->index_type = "w";
613 mk_tag_path_full(tag_path_full, sizeof(tag_path_full), n);
615 wrd->index_type = "0";
616 wrd->term_buf = tag_path_full;
617 wrd->term_len = strlen(tag_path_full);
618 wrd->index_name = xpath_index;
619 if (p->flagShowRecords)
621 printf("%*s tag=", (level + 1) * 4, "");
622 for (i = 0; i<wrd->term_len && i < 40; i++)
623 fputc(wrd->term_buf[i], stdout);
633 (*p->tokenAdd)(wrd); /* index element pag (AKA tag path) */
635 if (xpath_is_start == 1) /* only for the starting tag... */
637 #define MAX_ATTR_COUNT 50
638 data1_termlist *tll[MAX_ATTR_COUNT];
641 for (xp = n->u.tag.attributes; xp; xp = xp->next) {
643 char attr_tag_path_full[1024];
645 /* this could be cached as well */
646 sprintf(attr_tag_path_full, "@%s/%s",
647 xp->name, tag_path_full);
649 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);
684 for (xp = n->u.tag.attributes; xp; xp = xp->next) {
686 char attr_tag_path_full[1024];
689 sprintf(attr_tag_path_full, "@%s/%s",
690 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);
768 for (i = 0; i<wrd->term_len && i < 40; i++)
769 fputc(wrd->term_buf[i], stdout);
771 if (wrd->term_len > 40)
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)
893 if (n->u.root.absyn && n->u.root.absyn->oid)
894 (*p->schemaAdd)(p, n->u.root.absyn->oid);
897 /* data1_pr_tree(p->dh, n, stdout); */
899 return dumpkeys(n, p, &wrd);
902 static int grs_extract_sub(void *clientData, struct recExtractCtrl *p,
904 data1_node *(*grs_read)(struct grs_read_info *))
907 struct grs_read_info gri;
910 gri.stream = p->stream;
913 gri.clientData = clientData;
915 n = (*grs_read)(&gri);
917 return RECCTRL_EXTRACT_EOF;
918 if (n->u.root.absyn && n->u.root.absyn->oid)
919 (*p->schemaAdd)(p, n->u.root.absyn->oid);
920 data1_concat_text(p->dh, mem, n);
922 /* ensure our data1 tree is UTF-8 */
923 data1_iconv(p->dh, mem, n, "UTF-8", data1_get_encoding(p->dh, n));
926 data1_remove_idzebra_subtree(p->dh, n);
929 data1_pr_tree(p->dh, n, stdout);
933 if (dumpkeys(n, p, &wrd) < 0)
935 return RECCTRL_EXTRACT_ERROR_GENERIC;
937 return RECCTRL_EXTRACT_OK;
940 int zebra_grs_extract(void *clientData, struct recExtractCtrl *p,
941 data1_node *(*grs_read)(struct grs_read_info *))
944 NMEM mem = nmem_create();
945 ret = grs_extract_sub(clientData, p, mem, grs_read);
951 * Return: -1: Nothing done. 0: Ok. >0: Bib-1 diagnostic.
953 static int process_comp(data1_handle dh, data1_node *n, Z_RecordComposition *c,
954 char **addinfo, ODR o)
956 data1_esetname *eset;
962 case Z_RecordComp_simple:
963 if (c->u.simple->which != Z_ElementSetNames_generic)
964 return 26; /* only generic form supported. Fix this later */
965 if (!(eset = data1_getesetbyname(dh, n->u.root.absyn,
966 c->u.simple->u.generic)))
968 yaz_log(YLOG_LOG, "Unknown esetname '%s'", c->u.simple->u.generic);
969 *addinfo = odr_strdup(o, c->u.simple->u.generic);
970 return 25; /* invalid esetname */
972 yaz_log(YLOG_DEBUG, "Esetname '%s' in simple compspec",
973 c->u.simple->u.generic);
976 case Z_RecordComp_complex:
977 if (c->u.complex->generic)
979 /* insert check for schema */
980 if ((p = c->u.complex->generic->elementSpec))
984 case Z_ElementSpec_elementSetName:
986 data1_getesetbyname(dh, n->u.root.absyn,
987 p->u.elementSetName)))
989 yaz_log(YLOG_DEBUG, "Unknown esetname '%s'",
990 p->u.elementSetName);
991 *addinfo = odr_strdup(o, p->u.elementSetName);
992 return 25; /* invalid esetname */
994 yaz_log(YLOG_DEBUG, "Esetname '%s' in complex compspec",
995 p->u.elementSetName);
998 case Z_ElementSpec_externalSpec:
999 if (p->u.externalSpec->which == Z_External_espec1)
1001 yaz_log(YLOG_DEBUG, "Got Espec-1");
1002 espec = p->u.externalSpec-> u.espec1;
1006 yaz_log(YLOG_LOG, "Unknown external espec.");
1007 return 25; /* bad. what is proper diagnostic? */
1014 return 26; /* fix */
1018 yaz_log(YLOG_DEBUG, "Element: Espec-1 match");
1019 return data1_doespec1(dh, n, espec);
1023 yaz_log(YLOG_DEBUG, "Element: all match");
1028 /* Add Zebra info in separate namespace ...
1031 <metadata xmlns="http://www.indexdata.dk/zebra/">
1033 <localnumber>447</localnumber>
1034 <filename>records/genera.xml</filename>
1039 static void zebra_xml_metadata(struct recRetrieveCtrl *p, data1_node *top,
1042 const char *idzebra_ns[3];
1043 const char *i2 = "\n ";
1044 const char *i4 = "\n ";
1047 idzebra_ns[0] = "xmlns";
1048 idzebra_ns[1] = "http://www.indexdata.dk/zebra/";
1051 data1_mk_text(p->dh, mem, i2, top);
1053 n = data1_mk_tag(p->dh, mem, "idzebra", idzebra_ns, top);
1055 data1_mk_text(p->dh, mem, "\n", top);
1057 data1_mk_text(p->dh, mem, i4, n);
1059 data1_mk_tag_data_int(p->dh, n, "size", p->recordSize, mem);
1063 data1_mk_text(p->dh, mem, i4, n);
1064 data1_mk_tag_data_int(p->dh, n, "score", p->score, mem);
1066 data1_mk_text(p->dh, mem, i4, n);
1067 data1_mk_tag_data_zint(p->dh, n, "localnumber", p->localno, mem);
1070 data1_mk_text(p->dh, mem, i4, n);
1071 data1_mk_tag_data_text(p->dh, n, "filename", p->fname, mem);
1073 data1_mk_text(p->dh, mem, i2, n);
1076 int zebra_grs_retrieve(void *clientData, struct recRetrieveCtrl *p,
1077 data1_node *(*grs_read)(struct grs_read_info *))
1079 data1_node *node = 0, *onode = 0, *top;
1082 int res, selected = 0;
1084 struct grs_read_info gri;
1085 const char *tagname;
1087 const Odr_oid *requested_schema = 0;
1088 data1_marctab *marctab;
1091 mem = nmem_create();
1092 gri.stream = p->stream;
1095 gri.clientData = clientData;
1097 yaz_log(YLOG_DEBUG, "grs_retrieve");
1098 node = (*grs_read)(&gri);
1101 p->diagnostic = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
1105 data1_concat_text(p->dh, mem, node);
1107 data1_remove_idzebra_subtree(p->dh, node);
1110 data1_pr_tree(p->dh, node, stdout);
1112 top = data1_get_root_tag(p->dh, node);
1114 yaz_log(YLOG_DEBUG, "grs_retrieve: size");
1115 tagname = data1_systag_lookup(node->u.root.absyn, "size", "size");
1117 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1119 dnew->u.data.what = DATA1I_text;
1120 dnew->u.data.data = dnew->lbuf;
1121 sprintf(dnew->u.data.data, "%d", p->recordSize);
1122 dnew->u.data.len = strlen(dnew->u.data.data);
1125 tagname = data1_systag_lookup(node->u.root.absyn, "rank", "rank");
1126 if (tagname && p->score >= 0 &&
1127 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1129 yaz_log(YLOG_DEBUG, "grs_retrieve: %s", tagname);
1130 dnew->u.data.what = DATA1I_num;
1131 dnew->u.data.data = dnew->lbuf;
1132 sprintf(dnew->u.data.data, "%d", p->score);
1133 dnew->u.data.len = strlen(dnew->u.data.data);
1136 tagname = data1_systag_lookup(node->u.root.absyn, "sysno",
1137 "localControlNumber");
1138 if (tagname && p->localno > 0 &&
1139 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1141 yaz_log(YLOG_DEBUG, "grs_retrieve: %s", tagname);
1142 dnew->u.data.what = DATA1I_text;
1143 dnew->u.data.data = dnew->lbuf;
1145 sprintf(dnew->u.data.data, ZINT_FORMAT, p->localno);
1146 dnew->u.data.len = strlen(dnew->u.data.data);
1149 if (!p->input_format)
1150 { /* SUTRS is default input_format */
1151 p->input_format = yaz_oid_recsyn_sutrs;
1153 assert(p->input_format);
1155 if (!oid_oidcmp(p->input_format, yaz_oid_recsyn_xml))
1156 zebra_xml_metadata(p, top, mem);
1159 data1_pr_tree(p->dh, node, stdout);
1161 if (p->comp && p->comp->which == Z_RecordComp_complex &&
1162 p->comp->u.complex->generic &&
1163 p->comp->u.complex->generic->which == Z_Schema_oid &&
1164 p->comp->u.complex->generic->schema.oid)
1166 requested_schema = p->comp->u.complex->generic->schema.oid;
1168 /* If schema has been specified, map if possible, then check that
1169 * we got the right one
1171 if (requested_schema)
1173 yaz_log(YLOG_DEBUG, "grs_retrieve: schema mapping");
1174 for (map = node->u.root.absyn->maptabs; map; map = map->next)
1176 if (!oid_oidcmp(map->oid, requested_schema))
1179 if (!(node = data1_map_record(p->dh, onode, map, mem)))
1181 p->diagnostic = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
1188 if (node->u.root.absyn
1189 && oid_oidcmp(requested_schema, node->u.root.absyn->oid))
1191 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1197 * Does the requested format match a known syntax-mapping? (this reflects
1198 * the overlap of schema and formatting which is inherent in the MARC
1201 yaz_log(YLOG_DEBUG, "grs_retrieve: syntax mapping");
1202 if (node->u.root.absyn)
1203 for (map = node->u.root.absyn->maptabs; map; map = map->next)
1205 if (!oid_oidcmp(map->oid, p->input_format))
1208 if (!(node = data1_map_record(p->dh, onode, map, mem)))
1210 p->diagnostic = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
1217 yaz_log(YLOG_DEBUG, "grs_retrieve: schemaIdentifier");
1218 if (node->u.root.absyn && node->u.root.absyn->oid
1219 && !oid_oidcmp(p->input_format, yaz_oid_recsyn_grs_1))
1221 char oid_str[OID_STR_MAX];
1222 char *dot_str = oid_oid_to_dotstring(node->u.root.absyn->oid, oid_str);
1224 if (dot_str && (dnew = data1_mk_tag_data_wd(p->dh, top,
1225 "schemaIdentifier", mem)))
1227 dnew->u.data.what = DATA1I_oid;
1228 dnew->u.data.data = (char *) nmem_strdup(mem, dot_str);
1229 dnew->u.data.len = strlen(dot_str);
1233 yaz_log(YLOG_DEBUG, "grs_retrieve: element spec");
1234 if (p->comp && (res = process_comp(p->dh, node, p->comp, &p->addinfo,
1237 p->diagnostic = res;
1241 else if (p->comp && !res)
1245 data1_pr_tree(p->dh, node, stdout);
1247 yaz_log(YLOG_DEBUG, "grs_retrieve: transfer syntax mapping");
1249 p->output_format = p->input_format;
1251 assert(p->input_format);
1252 if (!oid_oidcmp(p->input_format, yaz_oid_recsyn_xml))
1255 data1_pr_tree(p->dh, node, stdout);
1257 /* default output encoding for XML is UTF-8 */
1258 data1_iconv(p->dh, mem, node,
1259 p->encoding ? p->encoding : "UTF-8",
1260 data1_get_encoding(p->dh, node));
1262 if (!(p->rec_buf = data1_nodetoidsgml(p->dh, node, selected,
1264 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1267 char *new_buf = (char*) odr_malloc(p->odr, p->rec_len);
1268 memcpy(new_buf, p->rec_buf, p->rec_len);
1269 p->rec_buf = new_buf;
1272 else if (!oid_oidcmp(p->input_format, yaz_oid_recsyn_grs_1))
1274 data1_iconv(p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1276 if (!(p->rec_buf = data1_nodetogr(p->dh, node, selected,
1278 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1282 else if (!oid_oidcmp(p->input_format, yaz_oid_recsyn_explain))
1284 /* ensure our data1 tree is UTF-8 */
1285 data1_iconv(p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1287 if (!(p->rec_buf = data1_nodetoexplain(p->dh, node, selected,
1289 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1293 else if (!oid_oidcmp(p->input_format, yaz_oid_recsyn_summary))
1295 /* ensure our data1 tree is UTF-8 */
1296 data1_iconv(p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1297 if (!(p->rec_buf = data1_nodetosummary(p->dh, node, selected,
1299 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1303 else if (!oid_oidcmp(p->input_format, yaz_oid_recsyn_sutrs))
1306 data1_iconv(p->dh, mem, node, p->encoding,
1307 data1_get_encoding(p->dh, node));
1308 if (!(p->rec_buf = data1_nodetobuf(p->dh, node, selected,
1310 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1313 char *new_buf = (char*) odr_malloc(p->odr, p->rec_len);
1314 memcpy(new_buf, p->rec_buf, p->rec_len);
1315 p->rec_buf = new_buf;
1318 else if (!oid_oidcmp(p->input_format, yaz_oid_recsyn_soif))
1321 data1_iconv(p->dh, mem, node, p->encoding,
1322 data1_get_encoding(p->dh, node));
1323 if (!(p->rec_buf = data1_nodetosoif(p->dh, node, selected,
1325 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1328 char *new_buf = (char*) odr_malloc(p->odr, p->rec_len);
1329 memcpy(new_buf, p->rec_buf, p->rec_len);
1330 p->rec_buf = new_buf;
1335 if (!node->u.root.absyn)
1336 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1339 for (marctab = node->u.root.absyn->marc; marctab;
1340 marctab = marctab->next)
1341 if (marctab->oid && !oid_oidcmp(marctab->oid, p->input_format))
1344 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1348 data1_iconv(p->dh, mem, node, p->encoding,
1349 data1_get_encoding(p->dh, node));
1350 if (!(p->rec_buf = data1_nodetomarc(p->dh, marctab, node,
1351 selected, &p->rec_len)))
1352 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
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;
1369 * c-file-style: "Stroustrup"
1370 * indent-tabs-mode: nil
1372 * vim: shiftwidth=4 tabstop=8 expandtab