1 /* This file is part of the Zebra server.
2 Copyright (C) 1994-2010 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
22 #include <sys/types.h>
26 #include <yaz/oid_db.h>
27 #include <yaz/diagbib1.h>
30 #include <idzebra/recgrs.h>
32 #define GRS_MAX_WORD 512
34 struct source_parser {
42 static int sp_lex(struct source_parser *sp)
44 while (*sp->src == ' ')
48 while (*sp->src && !strchr("<>();,-: ", *sp->src))
57 sp->lookahead = *sp->src;
64 static int sp_expr(struct source_parser *sp, data1_node *n, RecWord *wrd);
66 static int sp_range(struct source_parser *sp, data1_node *n, RecWord *wrd)
73 if (sp->lookahead != '(')
75 sp_lex(sp); /* skip ( */
78 if (!sp_expr(sp, n, wrd))
81 if (sp->lookahead != ',')
83 sp_lex(sp); /* skip , */
86 if (!sp_expr(sp, n, &tmp_w))
88 start = atoi_n(tmp_w.term_buf, tmp_w.term_len);
90 if (sp->lookahead == ',')
92 sp_lex(sp); /* skip , */
95 if (!sp_expr(sp, n, &tmp_w))
97 len = atoi_n(tmp_w.term_buf, tmp_w.term_len);
103 if (sp->lookahead != ')')
109 if (start >= wrd->term_len)
113 wrd->term_len -= start;
114 wrd->term_buf += start;
116 if (wrd->term_len > len)
123 static int sp_first(struct source_parser *sp, data1_node *n, RecWord *wrd)
128 if (sp->lookahead != '(')
130 sp_lex(sp); /* skip ( */
131 if (!sp_expr(sp, n, wrd))
133 while (sp->lookahead == ',')
137 sp_lex(sp); /* skip , */
139 if (!sp_expr(sp, n, &search_w))
141 for (i = 0; i<wrd->term_len; i++)
144 for (j = 0; j<search_w.term_len && i+j < wrd->term_len; j++)
145 if (wrd->term_buf[i+j] != search_w.term_buf[j])
147 if (j == search_w.term_len) /* match ? */
149 if (min_pos == -1 || i < min_pos)
155 if (sp->lookahead != ')')
159 min_pos = 0; /* the default if not found */
160 sprintf(num_str, "%d", min_pos);
161 wrd->term_buf = nmem_strdup(sp->nmem, num_str);
162 wrd->term_len = strlen(wrd->term_buf);
166 static int sp_expr(struct source_parser *sp, data1_node *n, RecWord *wrd)
168 if (sp->lookahead != 't')
170 if (sp->len == 4 && !memcmp(sp->tok, "data", sp->len))
172 if (n->which == DATA1N_data)
174 wrd->term_buf = n->u.data.data;
175 wrd->term_len = n->u.data.len;
179 else if (sp->len == 3 && !memcmp(sp->tok, "tag", sp->len))
181 if (n->which == DATA1N_tag)
183 wrd->term_buf = n->u.tag.tag;
184 wrd->term_len = strlen(n->u.tag.tag);
188 else if (sp->len == 4 && !memcmp(sp->tok, "attr", sp->len))
192 if (sp->lookahead != '(')
196 if (!sp_expr(sp, n, &tmp_w))
201 if (n->which == DATA1N_tag)
203 data1_xattr *p = n->u.tag.attributes;
204 while (p && strlen(p->name) != tmp_w.term_len &&
205 memcmp (p->name, tmp_w.term_buf, tmp_w.term_len))
209 wrd->term_buf = p->value;
210 wrd->term_len = strlen(p->value);
213 if (sp->lookahead != ')')
217 else if (sp->len == 5 && !memcmp(sp->tok, "first", sp->len))
219 return sp_first(sp, n, wrd);
221 else if (sp->len == 5 && !memcmp(sp->tok, "range", sp->len))
223 return sp_range(sp, n, wrd);
225 else if (sp->len > 0 && isdigit(*(unsigned char *)sp->tok))
228 wrd->term_len = sp->len;
229 b = nmem_malloc(sp->nmem, sp->len);
230 memcpy(b, sp->tok, sp->len);
234 else if (sp->len > 2 && sp->tok[0] == '\'' && sp->tok[sp->len-1] == '\'')
237 wrd->term_len = sp->len - 2;
238 b = nmem_malloc(sp->nmem, wrd->term_len);
239 memcpy(b, sp->tok+1, wrd->term_len);
252 static struct source_parser *source_parser_create(void)
254 struct source_parser *sp = xmalloc(sizeof(*sp));
256 sp->nmem = nmem_create();
260 static void source_parser_destroy(struct source_parser *sp)
264 nmem_destroy(sp->nmem);
268 static int sp_parse(struct source_parser *sp,
269 data1_node *n, RecWord *wrd, const char *src)
275 nmem_reset(sp->nmem);
278 return sp_expr(sp, n, wrd);
281 int d1_check_xpath_predicate(data1_node *n, struct xpath_predicate *p)
290 if (p->which == XPATH_PREDICATE_RELATION) {
291 if (p->u.relation.name[0]) {
292 if (*p->u.relation.name != '@') {
294 " Only attributes (@) are supported in xelm xpath predicates");
295 yaz_log(YLOG_WARN, "predicate %s ignored", p->u.relation.name);
298 attname = p->u.relation.name + 1;
300 /* looking for the attribute with a specified name */
301 for (attr = n->u.tag.attributes; attr; attr = attr->next) {
302 if (!strcmp(attr->name, attname)) {
303 if (p->u.relation.op[0]) {
304 if (*p->u.relation.op != '=') {
306 "Only '=' relation is supported (%s)",p->u.relation.op);
307 yaz_log(YLOG_WARN, "predicate %s ignored", p->u.relation.name);
310 if (!strcmp(attr->value, p->u.relation.value)) {
315 /* attribute exists, no value specified */
325 else if (p->which == XPATH_PREDICATE_BOOLEAN) {
326 if (!strcmp(p->u.boolean.op,"and")) {
327 return d1_check_xpath_predicate(n, p->u.boolean.left)
328 && d1_check_xpath_predicate(n, p->u.boolean.right);
330 else if (!strcmp(p->u.boolean.op,"or")) {
331 return (d1_check_xpath_predicate(n, p->u.boolean.left)
332 || d1_check_xpath_predicate(n, p->u.boolean.right));
334 yaz_log(YLOG_WARN, "Unknown boolean relation %s, ignored",p->u.boolean.op);
343 static int dfa_match_first(struct DFA_state **dfaar, const char *text)
345 struct DFA_state *s = dfaar[0]; /* start state */
348 const char *p = text;
351 for (c = *p++, t = s->trans, i = s->tran_no; --i >= 0; t++)
353 if (c >= t->ch[0] && c <= t->ch[1])
357 /* move to next state and return if we get a match */
365 for (t = s->trans, i = s->tran_no; --i >= 0; t++)
366 if (c >= t->ch[0] && c <= t->ch[1])
376 New function, looking for xpath "element" definitions in abs, by
377 tagpath, using a kind of ugly regxp search.The DFA was built while
378 parsing abs, so here we just go trough them and try to match
379 against the given tagpath. The first matching entry is returned.
383 Added support for enhanced xelm. Now [] predicates are considered
384 as well, when selecting indexing rules... (why the hell it's called
391 data1_termlist *xpath_termlist_by_tagpath(char *tagpath, data1_node *n)
393 data1_absyn *abs = n->root->u.root.absyn;
395 data1_xpelement *xpe = 0;
398 struct xpath_location_step *xp;
400 char *pexpr = xmalloc(strlen(tagpath)+5);
402 sprintf(pexpr, "/%s\n", tagpath);
404 for (xpe = abs->xp_elements; xpe; xpe = xpe->next)
405 xpe->match_state = -1; /* don't know if it matches yet */
407 for (xpe = abs->xp_elements; xpe; xpe = xpe->next)
410 int ok = xpe->match_state;
412 { /* don't know whether there is a match yet */
413 data1_xpelement *xpe1;
416 ok = dfa_match_first(xpe->dfa->states, pexpr);
419 /* mark this and following ones with same regexp */
420 for (xpe1 = xpe; xpe1; xpe1 = xpe1->match_next)
421 xpe1->match_state = ok;
424 assert(ok == 0 || ok == 1);
427 /* we have to check the perdicates up to the root node */
430 /* find the first tag up in the node structure */
431 for (nn = n; nn && nn->which != DATA1N_tag; nn = nn->parent)
434 /* go from inside out in the node structure, while going
435 backwards trough xpath location steps ... */
436 for (i = xpe->xpath_len - 1; i>0; i--)
438 if (!d1_check_xpath_predicate(nn, xp[i].predicate))
444 if (nn->which == DATA1N_tag)
456 return xpe->termlists;
463 1 start element (tag)
465 3 start attr (and attr-exact)
473 Now, if there is a matching xelm described in abs, for the
474 indexed element or the attribute, then the data is handled according
475 to those definitions...
477 modified by pop, 2002-12-13
480 /* add xpath index for an attribute */
481 static void index_xpath_attr(char *tag_path, char *name, char *value,
482 char *structure, struct recExtractCtrl *p,
485 wrd->index_name = ZEBRA_XPATH_ELM_BEGIN;
486 wrd->index_type = "0";
487 wrd->term_buf = tag_path;
488 wrd->term_len = strlen(tag_path);
492 wrd->index_name = ZEBRA_XPATH_ATTR_CDATA;
493 wrd->index_type = "w";
494 wrd->term_buf = value;
495 wrd->term_len = strlen(value);
498 wrd->index_name = ZEBRA_XPATH_ELM_END;
499 wrd->index_type = "0";
500 wrd->term_buf = tag_path;
501 wrd->term_len = strlen(tag_path);
506 static void mk_tag_path_full(char *tag_path_full, size_t max, data1_node *n)
511 /* we have to fetch the whole path to the data tag */
512 for (nn = n; nn; nn = nn->parent)
514 if (nn->which == DATA1N_tag)
516 size_t tlen = strlen(nn->u.tag.tag);
517 if (tlen + flen > (max - 2))
519 memcpy(tag_path_full + flen, nn->u.tag.tag, tlen);
521 tag_path_full[flen++] = '/';
524 if (nn->which == DATA1N_root)
527 tag_path_full[flen] = 0;
531 static void index_xpath(struct source_parser *sp, data1_node *n,
532 struct recExtractCtrl *p,
533 int level, RecWord *wrd,
539 char tag_path_full[1024];
540 int termlist_only = 1;
543 if (!n->root->u.root.absyn
545 n->root->u.root.absyn->xpath_indexing == DATA1_XPATH_INDEXING_ENABLE)
554 wrd->term_buf = n->u.data.data;
555 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);
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)
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 && !termlist_only)
604 wrd->index_name = xpath_index;
605 wrd->index_type = "w";
610 mk_tag_path_full(tag_path_full, sizeof(tag_path_full), n);
612 wrd->index_type = "0";
613 wrd->term_buf = tag_path_full;
614 wrd->term_len = strlen(tag_path_full);
615 wrd->index_name = xpath_index;
616 if (p->flagShowRecords)
618 printf("%*s tag=", (level + 1) * 4, "");
619 for (i = 0; i<wrd->term_len && i < 40; i++)
620 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);
650 /* attribute (no value) */
651 wrd->index_type = "0";
652 wrd->index_name = ZEBRA_XPATH_ATTR_NAME;
653 wrd->term_buf = xp->name;
654 wrd->term_len = strlen(xp->name);
661 strlen(xp->name) + strlen(xp->value) < sizeof(comb)-2)
663 /* attribute value exact */
664 strcpy(comb, xp->name);
666 strcat(comb, xp->value);
668 wrd->index_name = ZEBRA_XPATH_ATTR_NAME;
669 wrd->index_type = "0";
670 wrd->term_buf = comb;
671 wrd->term_len = strlen(comb);
681 for (xp = n->u.tag.attributes; xp; xp = xp->next) {
683 char attr_tag_path_full[1024];
686 sprintf(attr_tag_path_full, "@%s/%s",
687 xp->name, tag_path_full);
690 /* If there is a termlist given (=xelm directive) */
691 for (; tl; tl = tl->next)
695 /* add xpath index for the attribute */
696 index_xpath_attr(attr_tag_path_full, xp->name,
697 xp->value, tl->structure,
701 /* index attribute value (only path/@attr) */
704 wrd->index_name = tl->index_name;
705 wrd->index_type = tl->structure;
706 wrd->term_buf = xp->value;
707 wrd->term_len = strlen(xp->value);
713 /* if there was no termlist for the given path,
714 or the termlist didn't have a ! element, index
715 the attribute as "w" */
716 if (!xpdone && !termlist_only)
718 index_xpath_attr(attr_tag_path_full, xp->name,
719 xp->value, "w", p, wrd);
728 static void index_termlist(struct source_parser *sp, data1_node *par,
730 struct recExtractCtrl *p, int level, RecWord *wrd)
732 data1_termlist *tlist = 0;
733 data1_datatype dtype = DATA1K_string;
736 * cycle up towards the root until we find a tag with an att..
737 * this has the effect of indexing locally defined tags with
738 * the attribute of their ancestor in the record.
741 while (!par->u.tag.element)
742 if (!par->parent || !(par=get_parent_tag(p->dh, par->parent)))
744 if (!par || !(tlist = par->u.tag.element->termlists))
746 if (par->u.tag.element->tag)
747 dtype = par->u.tag.element->tag->kind;
749 for (; tlist; tlist = tlist->next)
751 /* consider source */
753 assert(tlist->source);
754 sp_parse(sp, n, wrd, tlist->source);
756 if (wrd->term_buf && wrd->term_len)
758 if (p->flagShowRecords)
761 printf("%*sIdx: [%s]", (level + 1) * 4, "",
763 printf("%s %s", tlist->index_name, tlist->source);
765 for (i = 0; i<wrd->term_len && i < 40; i++)
766 fputc(wrd->term_buf[i], stdout);
768 if (wrd->term_len > 40)
774 wrd->index_type = tlist->structure;
775 wrd->index_name = tlist->index_name;
782 static int dumpkeys_r(struct source_parser *sp,
783 data1_node *n, struct recExtractCtrl *p, int level,
786 for (; n; n = n->next)
788 if (p->flagShowRecords) /* display element description to user */
790 if (n->which == DATA1N_root)
792 printf("%*s", level * 4, "");
793 printf("Record type: '%s'\n", n->u.root.type);
795 else if (n->which == DATA1N_tag)
799 printf("%*s", level * 4, "");
800 if (!(e = n->u.tag.element))
801 printf("Local tag: '%s'\n", n->u.tag.tag);
804 printf("Elm: '%s' ", e->name);
807 data1_tag *t = e->tag;
809 printf("TagNam: '%s' ", t->names->name);
812 printf("%s[%d],", t->tagset->name, t->tagset->type);
815 if (t->which == DATA1T_numeric)
816 printf("%d)", t->value.numeric);
818 printf("'%s')", t->value.string);
825 if (n->which == DATA1N_tag)
827 index_termlist(sp, n, n, p, level, wrd);
828 /* index start tag */
829 if (n->root->u.root.absyn)
830 index_xpath(sp, n, p, level, wrd, ZEBRA_XPATH_ELM_BEGIN,
835 if (dumpkeys_r(sp, n->child, p, level + 1, wrd) < 0)
839 if (n->which == DATA1N_data)
841 data1_node *par = get_parent_tag(p->dh, n);
843 if (p->flagShowRecords)
845 printf("%*s", level * 4, "");
847 if (n->u.data.len > 256)
848 printf("'%.170s ... %.70s'\n", n->u.data.data,
849 n->u.data.data + n->u.data.len-70);
850 else if (n->u.data.len > 0)
851 printf("'%.*s'\n", n->u.data.len, n->u.data.data);
857 index_termlist(sp, par, n, p, level, wrd);
859 index_xpath(sp, n, p, level, wrd, ZEBRA_XPATH_CDATA,
863 if (n->which == DATA1N_tag)
866 index_xpath(sp, n, p, level, wrd, ZEBRA_XPATH_ELM_END,
870 if (p->flagShowRecords && n->which == DATA1N_root)
872 printf("%*s-------------\n\n", level * 4, "");
878 static int dumpkeys(data1_node *n, struct recExtractCtrl *p, RecWord *wrd)
880 struct source_parser *sp = source_parser_create();
881 int r = dumpkeys_r(sp, n, p, 0, wrd);
882 source_parser_destroy(sp);
886 int grs_extract_tree(struct recExtractCtrl *p, data1_node *n)
890 if (n->u.root.absyn && n->u.root.absyn->oid)
891 (*p->schemaAdd)(p, n->u.root.absyn->oid);
894 /* data1_pr_tree(p->dh, n, stdout); */
896 return dumpkeys(n, p, &wrd);
899 static int grs_extract_sub(void *clientData, struct recExtractCtrl *p,
901 data1_node *(*grs_read)(struct grs_read_info *))
904 struct grs_read_info gri;
907 gri.stream = p->stream;
910 gri.clientData = clientData;
912 n = (*grs_read)(&gri);
914 return RECCTRL_EXTRACT_EOF;
915 if (n->u.root.absyn && n->u.root.absyn->oid)
916 (*p->schemaAdd)(p, n->u.root.absyn->oid);
917 data1_concat_text(p->dh, mem, n);
919 /* ensure our data1 tree is UTF-8 */
920 data1_iconv(p->dh, mem, n, "UTF-8", data1_get_encoding(p->dh, n));
923 data1_remove_idzebra_subtree(p->dh, n);
926 data1_pr_tree(p->dh, n, stdout);
930 if (dumpkeys(n, p, &wrd) < 0)
932 return RECCTRL_EXTRACT_ERROR_GENERIC;
934 return RECCTRL_EXTRACT_OK;
937 int zebra_grs_extract(void *clientData, struct recExtractCtrl *p,
938 data1_node *(*grs_read)(struct grs_read_info *))
941 NMEM mem = nmem_create();
942 ret = grs_extract_sub(clientData, p, mem, grs_read);
948 * Return: -1: Nothing done. 0: Ok. >0: Bib-1 diagnostic.
950 static int process_comp(data1_handle dh, data1_node *n, Z_RecordComposition *c,
951 char **addinfo, ODR o)
953 data1_esetname *eset;
959 case Z_RecordComp_simple:
960 if (c->u.simple->which != Z_ElementSetNames_generic)
961 return 26; /* only generic form supported. Fix this later */
962 if (!(eset = data1_getesetbyname(dh, n->u.root.absyn,
963 c->u.simple->u.generic)))
965 yaz_log(YLOG_LOG, "Unknown esetname '%s'", c->u.simple->u.generic);
966 *addinfo = odr_strdup(o, c->u.simple->u.generic);
967 return 25; /* invalid esetname */
969 yaz_log(YLOG_DEBUG, "Esetname '%s' in simple compspec",
970 c->u.simple->u.generic);
973 case Z_RecordComp_complex:
974 if (c->u.complex->generic)
976 /* insert check for schema */
977 if ((p = c->u.complex->generic->elementSpec))
981 case Z_ElementSpec_elementSetName:
983 data1_getesetbyname(dh, n->u.root.absyn,
984 p->u.elementSetName)))
986 yaz_log(YLOG_DEBUG, "Unknown esetname '%s'",
987 p->u.elementSetName);
988 *addinfo = odr_strdup(o, p->u.elementSetName);
989 return 25; /* invalid esetname */
991 yaz_log(YLOG_DEBUG, "Esetname '%s' in complex compspec",
992 p->u.elementSetName);
995 case Z_ElementSpec_externalSpec:
996 if (p->u.externalSpec->which == Z_External_espec1)
998 yaz_log(YLOG_DEBUG, "Got Espec-1");
999 espec = p->u.externalSpec-> u.espec1;
1003 yaz_log(YLOG_LOG, "Unknown external espec.");
1004 return 25; /* bad. what is proper diagnostic? */
1011 return 26; /* fix */
1015 yaz_log(YLOG_DEBUG, "Element: Espec-1 match");
1016 return data1_doespec1(dh, n, espec);
1020 yaz_log(YLOG_DEBUG, "Element: all match");
1025 /* Add Zebra info in separate namespace ...
1028 <metadata xmlns="http://www.indexdata.dk/zebra/">
1030 <localnumber>447</localnumber>
1031 <filename>records/genera.xml</filename>
1036 static void zebra_xml_metadata(struct recRetrieveCtrl *p, data1_node *top,
1039 const char *idzebra_ns[3];
1040 const char *i2 = "\n ";
1041 const char *i4 = "\n ";
1044 idzebra_ns[0] = "xmlns";
1045 idzebra_ns[1] = "http://www.indexdata.dk/zebra/";
1048 data1_mk_text(p->dh, mem, i2, top);
1050 n = data1_mk_tag(p->dh, mem, "idzebra", idzebra_ns, top);
1052 data1_mk_text(p->dh, mem, "\n", top);
1054 data1_mk_text(p->dh, mem, i4, n);
1056 data1_mk_tag_data_int(p->dh, n, "size", p->recordSize, mem);
1060 data1_mk_text(p->dh, mem, i4, n);
1061 data1_mk_tag_data_int(p->dh, n, "score", p->score, mem);
1063 data1_mk_text(p->dh, mem, i4, n);
1064 data1_mk_tag_data_zint(p->dh, n, "localnumber", p->localno, mem);
1067 data1_mk_text(p->dh, mem, i4, n);
1068 data1_mk_tag_data_text(p->dh, n, "filename", p->fname, mem);
1070 data1_mk_text(p->dh, mem, i2, n);
1073 int zebra_grs_retrieve(void *clientData, struct recRetrieveCtrl *p,
1074 data1_node *(*grs_read)(struct grs_read_info *))
1076 data1_node *node = 0, *onode = 0, *top;
1079 int res, selected = 0;
1081 struct grs_read_info gri;
1082 const char *tagname;
1084 const Odr_oid *requested_schema = 0;
1085 data1_marctab *marctab;
1088 mem = nmem_create();
1089 gri.stream = p->stream;
1092 gri.clientData = clientData;
1094 yaz_log(YLOG_DEBUG, "grs_retrieve");
1095 node = (*grs_read)(&gri);
1098 p->diagnostic = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
1102 data1_concat_text(p->dh, mem, node);
1104 data1_remove_idzebra_subtree(p->dh, node);
1107 data1_pr_tree(p->dh, node, stdout);
1109 top = data1_get_root_tag(p->dh, node);
1111 yaz_log(YLOG_DEBUG, "grs_retrieve: size");
1112 tagname = data1_systag_lookup(node->u.root.absyn, "size", "size");
1114 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1116 dnew->u.data.what = DATA1I_text;
1117 dnew->u.data.data = dnew->lbuf;
1118 sprintf(dnew->u.data.data, "%d", p->recordSize);
1119 dnew->u.data.len = strlen(dnew->u.data.data);
1122 tagname = data1_systag_lookup(node->u.root.absyn, "rank", "rank");
1123 if (tagname && p->score >= 0 &&
1124 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1126 yaz_log(YLOG_DEBUG, "grs_retrieve: %s", tagname);
1127 dnew->u.data.what = DATA1I_num;
1128 dnew->u.data.data = dnew->lbuf;
1129 sprintf(dnew->u.data.data, "%d", p->score);
1130 dnew->u.data.len = strlen(dnew->u.data.data);
1133 tagname = data1_systag_lookup(node->u.root.absyn, "sysno",
1134 "localControlNumber");
1135 if (tagname && p->localno > 0 &&
1136 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1138 yaz_log(YLOG_DEBUG, "grs_retrieve: %s", tagname);
1139 dnew->u.data.what = DATA1I_text;
1140 dnew->u.data.data = dnew->lbuf;
1142 sprintf(dnew->u.data.data, ZINT_FORMAT, p->localno);
1143 dnew->u.data.len = strlen(dnew->u.data.data);
1146 if (!p->input_format)
1147 { /* SUTRS is default input_format */
1148 p->input_format = yaz_oid_recsyn_sutrs;
1150 assert(p->input_format);
1152 if (!oid_oidcmp(p->input_format, yaz_oid_recsyn_xml))
1153 zebra_xml_metadata(p, top, mem);
1156 data1_pr_tree(p->dh, node, stdout);
1158 if (p->comp && p->comp->which == Z_RecordComp_complex &&
1159 p->comp->u.complex->generic &&
1160 p->comp->u.complex->generic->which == Z_Schema_oid &&
1161 p->comp->u.complex->generic->schema.oid)
1163 requested_schema = p->comp->u.complex->generic->schema.oid;
1165 /* If schema has been specified, map if possible, then check that
1166 * we got the right one
1168 if (requested_schema)
1170 yaz_log(YLOG_DEBUG, "grs_retrieve: schema mapping");
1171 for (map = node->u.root.absyn->maptabs; map; map = map->next)
1173 if (!oid_oidcmp(map->oid, requested_schema))
1176 if (!(node = data1_map_record(p->dh, onode, map, mem)))
1178 p->diagnostic = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
1185 if (node->u.root.absyn
1186 && oid_oidcmp(requested_schema, node->u.root.absyn->oid))
1188 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1194 * Does the requested format match a known syntax-mapping? (this reflects
1195 * the overlap of schema and formatting which is inherent in the MARC
1198 yaz_log(YLOG_DEBUG, "grs_retrieve: syntax mapping");
1199 if (node->u.root.absyn)
1200 for (map = node->u.root.absyn->maptabs; map; map = map->next)
1202 if (!oid_oidcmp(map->oid, p->input_format))
1205 if (!(node = data1_map_record(p->dh, onode, map, mem)))
1207 p->diagnostic = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
1214 yaz_log(YLOG_DEBUG, "grs_retrieve: schemaIdentifier");
1215 if (node->u.root.absyn && node->u.root.absyn->oid
1216 && !oid_oidcmp(p->input_format, yaz_oid_recsyn_grs_1))
1218 char oid_str[OID_STR_MAX];
1219 char *dot_str = oid_oid_to_dotstring(node->u.root.absyn->oid, oid_str);
1221 if (dot_str && (dnew = data1_mk_tag_data_wd(p->dh, top,
1222 "schemaIdentifier", mem)))
1224 dnew->u.data.what = DATA1I_oid;
1225 dnew->u.data.data = (char *) nmem_strdup(mem, dot_str);
1226 dnew->u.data.len = strlen(dot_str);
1230 yaz_log(YLOG_DEBUG, "grs_retrieve: element spec");
1231 if (p->comp && (res = process_comp(p->dh, node, p->comp, &p->addinfo,
1234 p->diagnostic = res;
1238 else if (p->comp && !res)
1242 data1_pr_tree(p->dh, node, stdout);
1244 yaz_log(YLOG_DEBUG, "grs_retrieve: transfer syntax mapping");
1246 p->output_format = p->input_format;
1248 assert(p->input_format);
1249 if (!oid_oidcmp(p->input_format, yaz_oid_recsyn_xml))
1252 data1_pr_tree(p->dh, node, stdout);
1254 /* default output encoding for XML is UTF-8 */
1255 data1_iconv(p->dh, mem, node,
1256 p->encoding ? p->encoding : "UTF-8",
1257 data1_get_encoding(p->dh, node));
1259 if (!(p->rec_buf = data1_nodetoidsgml(p->dh, node, selected,
1261 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1264 char *new_buf = (char*) odr_malloc(p->odr, p->rec_len);
1265 memcpy(new_buf, p->rec_buf, p->rec_len);
1266 p->rec_buf = new_buf;
1269 else if (!oid_oidcmp(p->input_format, yaz_oid_recsyn_grs_1))
1271 data1_iconv(p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1273 if (!(p->rec_buf = data1_nodetogr(p->dh, node, selected,
1275 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1279 else if (!oid_oidcmp(p->input_format, yaz_oid_recsyn_explain))
1281 /* ensure our data1 tree is UTF-8 */
1282 data1_iconv(p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1284 if (!(p->rec_buf = data1_nodetoexplain(p->dh, node, selected,
1286 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1290 else if (!oid_oidcmp(p->input_format, yaz_oid_recsyn_summary))
1292 /* ensure our data1 tree is UTF-8 */
1293 data1_iconv(p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1294 if (!(p->rec_buf = data1_nodetosummary(p->dh, node, selected,
1296 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1300 else if (!oid_oidcmp(p->input_format, yaz_oid_recsyn_sutrs))
1303 data1_iconv(p->dh, mem, node, p->encoding,
1304 data1_get_encoding(p->dh, node));
1305 if (!(p->rec_buf = data1_nodetobuf(p->dh, node, selected,
1307 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1310 char *new_buf = (char*) odr_malloc(p->odr, p->rec_len);
1311 memcpy(new_buf, p->rec_buf, p->rec_len);
1312 p->rec_buf = new_buf;
1315 else if (!oid_oidcmp(p->input_format, yaz_oid_recsyn_soif))
1318 data1_iconv(p->dh, mem, node, p->encoding,
1319 data1_get_encoding(p->dh, node));
1320 if (!(p->rec_buf = data1_nodetosoif(p->dh, node, selected,
1322 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1325 char *new_buf = (char*) odr_malloc(p->odr, p->rec_len);
1326 memcpy(new_buf, p->rec_buf, p->rec_len);
1327 p->rec_buf = new_buf;
1332 if (!node->u.root.absyn)
1333 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1336 for (marctab = node->u.root.absyn->marc; marctab;
1337 marctab = marctab->next)
1338 if (marctab->oid && !oid_oidcmp(marctab->oid, p->input_format))
1341 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1345 data1_iconv(p->dh, mem, node, p->encoding,
1346 data1_get_encoding(p->dh, node));
1347 if (!(p->rec_buf = data1_nodetomarc(p->dh, marctab, node,
1348 selected, &p->rec_len)))
1349 p->diagnostic = YAZ_BIB1_RECORD_NOT_AVAILABLE_IN_REQUESTED_SYNTAX;
1352 char *new_buf = (char*) odr_malloc(p->odr, p->rec_len);
1353 memcpy(new_buf, p->rec_buf, p->rec_len);
1354 p->rec_buf = new_buf;
1366 * c-file-style: "Stroustrup"
1367 * indent-tabs-mode: nil
1369 * vim: shiftwidth=4 tabstop=8 expandtab