1 /* $Id: recgrs.c,v 1.101 2005-04-29 23:09:30 adam Exp $
2 Copyright (C) 1995-2005
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 Zebra; see the file LICENSE.zebra. If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
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))
223 wrd->term_buf = nmem_malloc(sp->nmem, sp->len);
224 memcpy(wrd->term_buf, sp->tok, sp->len);
225 wrd->term_len = sp->len;
228 else if (sp->len > 2 && sp->tok[0] == '\'' && sp->tok[sp->len-1] == '\'')
230 wrd->term_len = sp->len - 2;
231 wrd->term_buf = nmem_malloc(sp->nmem, wrd->term_len);
232 memcpy(wrd->term_buf, sp->tok+1, wrd->term_len);
244 static struct source_parser *source_parser_create()
246 struct source_parser *sp = xmalloc(sizeof(*sp));
248 sp->nmem = nmem_create();
252 static void source_parser_destroy(struct source_parser *sp)
256 nmem_destroy(sp->nmem);
260 static int sp_parse(struct source_parser *sp,
261 data1_node *n, RecWord *wrd, const char *src)
267 nmem_reset(sp->nmem);
270 return sp_expr(sp, n, wrd);
273 int d1_check_xpath_predicate(data1_node *n, struct xpath_predicate *p)
282 if (p->which == XPATH_PREDICATE_RELATION) {
283 if (p->u.relation.name[0]) {
284 if (*p->u.relation.name != '@') {
286 " Only attributes (@) are supported in xelm xpath predicates");
287 yaz_log(YLOG_WARN, "predicate %s ignored", p->u.relation.name);
290 attname = p->u.relation.name + 1;
292 /* looking for the attribute with a specified name */
293 for (attr = n->u.tag.attributes; attr; attr = attr->next) {
294 yaz_log(YLOG_DEBUG," - attribute %s <-> %s", attname, attr->name );
296 if (!strcmp(attr->name, attname)) {
297 if (p->u.relation.op[0]) {
298 if (*p->u.relation.op != '=') {
300 "Only '=' relation is supported (%s)",p->u.relation.op);
301 yaz_log(YLOG_WARN, "predicate %s ignored", p->u.relation.name);
304 yaz_log(YLOG_DEBUG," - value %s <-> %s",
305 p->u.relation.value, attr->value );
306 if (!strcmp(attr->value, p->u.relation.value)) {
311 /* attribute exists, no value specified */
316 yaz_log(YLOG_DEBUG, "return %d", res);
322 else if (p->which == XPATH_PREDICATE_BOOLEAN) {
323 if (!strcmp(p->u.boolean.op,"and")) {
324 return d1_check_xpath_predicate(n, p->u.boolean.left)
325 && d1_check_xpath_predicate(n, p->u.boolean.right);
327 else if (!strcmp(p->u.boolean.op,"or")) {
328 return (d1_check_xpath_predicate(n, p->u.boolean.left)
329 || d1_check_xpath_predicate(n, p->u.boolean.right));
331 yaz_log(YLOG_WARN, "Unknown boolean relation %s, ignored",p->u.boolean.op);
342 New function, looking for xpath "element" definitions in abs, by
343 tagpath, using a kind of ugly regxp search.The DFA was built while
344 parsing abs, so here we just go trough them and try to match
345 against the given tagpath. The first matching entry is returned.
349 Added support for enhanced xelm. Now [] predicates are considered
350 as well, when selecting indexing rules... (why the hell it's called
357 data1_termlist *xpath_termlist_by_tagpath(char *tagpath, data1_node *n)
359 data1_absyn *abs = n->root->u.root.absyn;
360 data1_xpelement *xpe = abs->xp_elements;
363 struct xpath_location_step *xp;
365 char *pexpr = xmalloc(strlen(tagpath)+2);
368 sprintf (pexpr, "%s\n", tagpath);
369 yaz_log(YLOG_DEBUG, "Checking tagpath %s",tagpath);
370 for (; xpe; xpe = xpe->next)
372 struct DFA_state **dfaar = xpe->dfa->states;
373 struct DFA_state *s = dfaar[0];
374 struct DFA_tran *t = s->trans;
376 unsigned char c = *pexpr++;
379 if ((c >= t->ch[0] && c <= t->ch[1]) || (!t->ch[0]))
381 const char *p = pexpr;
384 if ((s = dfaar[t->to])->rule_no &&
385 (start_line || s->rule_nno))
390 for (t=s->trans, i=s->tran_no; --i >= 0; t++)
391 if ((unsigned) *p >= t->ch[0] && (unsigned) *p <= t->ch[1])
398 yaz_log(YLOG_DEBUG, " xpath match %s",xpe->xpath_expr);
400 yaz_log(YLOG_DEBUG, " xpath no match %s",xpe->xpath_expr);
405 /* we have to check the perdicates up to the root node */
408 /* find the first tag up in the node structure */
409 for (nn = n; nn && nn->which != DATA1N_tag; nn = nn->parent)
412 /* go from inside out in the node structure, while going
413 backwards trough xpath location steps ... */
414 for (i = xpe->xpath_len - 1; i>0; i--)
416 yaz_log(YLOG_DEBUG, "Checking step %d: %s on tag %s",
417 i, xp[i].part, nn->u.tag.tag);
419 if (!d1_check_xpath_predicate(nn, xp[i].predicate))
421 yaz_log(YLOG_DEBUG, " Predicates didn't match");
426 if (nn->which == DATA1N_tag)
438 yaz_log(YLOG_DEBUG, "Got it");
439 return xpe->termlists;
446 1 start element (tag)
448 3 start attr (and attr-exact)
456 Now, if there is a matching xelm described in abs, for the
457 indexed element or the attribute, then the data is handled according
458 to those definitions...
460 modified by pop, 2002-12-13
463 /* add xpath index for an attribute */
464 static void index_xpath_attr (char *tag_path, char *name, char *value,
465 char *structure, struct recExtractCtrl *p,
468 wrd->attrSet = VAL_IDXPATH;
471 wrd->term_buf = tag_path;
472 wrd->term_len = strlen(tag_path);
478 wrd->term_buf = value;
479 wrd->term_len = strlen(value);
485 wrd->term_buf = tag_path;
486 wrd->term_len = strlen(tag_path);
491 static void index_xpath (struct source_parser *sp, data1_node *n,
492 struct recExtractCtrl *p,
493 int level, RecWord *wrd, int use)
496 char tag_path_full[1024];
499 int termlist_only = 1;
503 yaz_log(YLOG_DEBUG, "index_xpath level=%d use=%d", level, use);
504 if ((!n->root->u.root.absyn) ||
505 (n->root->u.root.absyn->enable_xpath_indexing)) {
512 wrd->term_buf = n->u.data.data;
513 wrd->term_len = n->u.data.len;
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 > (sizeof(tag_path_full)-2))
525 memcpy (tag_path_full + flen, nn->u.tag.tag, tlen);
527 tag_path_full[flen++] = '/';
530 if (nn->which == DATA1N_root)
534 tag_path_full[flen] = 0;
536 /* If we have a matching termlist... */
537 if (n->root->u.root.absyn &&
538 (tl = xpath_termlist_by_tagpath(tag_path_full, n)))
540 for (; tl; tl = tl->next)
542 /* need to copy recword because it may be changed */
544 wrd->reg_type = *tl->structure;
545 /* this is the ! case, so structure is for the xpath index */
546 memcpy (&wrd_tl, wrd, sizeof(*wrd));
548 sp_parse(sp, n, &wrd_tl, tl->source);
550 wrd_tl.attrSet = VAL_IDXPATH;
551 wrd_tl.attrUse = use;
552 if (p->flagShowRecords)
555 printf("%*sXPath index", (level + 1) * 4, "");
556 printf (" XData:\"");
557 for (i = 0; i<wrd_tl.term_len && i < 40; i++)
558 fputc (wrd_tl.term_buf[i], stdout);
560 if (wrd_tl.term_len > 40)
562 fputc ('\n', stdout);
565 (*p->tokenAdd)(&wrd_tl);
568 /* this is just the old fashioned attribute based index */
569 wrd_tl.attrSet = (int) (tl->att->parent->reference);
570 wrd_tl.attrUse = tl->att->locals->local;
571 if (p->flagShowRecords)
574 printf("%*sIdx: [%s]", (level + 1) * 4, "",
576 printf("%s:%s [%d] %s",
577 tl->att->parent->name,
578 tl->att->name, tl->att->value,
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);
589 (*p->tokenAdd)(&wrd_tl);
593 /* xpath indexing is done, if there was no termlist given,
594 or no ! in the termlist, and default indexing is enabled... */
595 if (!p->flagShowRecords && !xpdone && !termlist_only)
597 wrd->attrSet = VAL_IDXPATH;
605 for (nn = n; nn; nn = nn->parent)
607 if (nn->which == DATA1N_tag)
609 size_t tlen = strlen(nn->u.tag.tag);
610 if (tlen + flen > (sizeof(tag_path_full)-2))
612 memcpy (tag_path_full + flen, nn->u.tag.tag, tlen);
614 tag_path_full[flen++] = '/';
616 else if (nn->which == DATA1N_root)
622 wrd->term_buf = tag_path_full;
623 wrd->term_len = flen;
624 wrd->attrSet = VAL_IDXPATH;
626 if (p->flagShowRecords)
628 printf("%*s tag=", (level + 1) * 4, "");
629 for (i = 0; i<wrd->term_len && i < 40; i++)
630 fputc (wrd->term_buf[i], stdout);
641 tag_path_full[flen] = 0;
643 /* Add tag start/end xpath index, only when there is a ! in the apropriate xelm
644 directive, or default xpath indexing is enabled */
645 if (!(do_xpindex = 1 - termlist_only)) {
646 if ((tl = xpath_termlist_by_tagpath(tag_path_full, n))) {
647 for (; tl; tl = tl->next) { if (!tl->att) {do_xpindex = 1;} }
651 (*p->tokenAdd)(wrd); /* index element pag (AKA tag path) */
654 if (use == 1) /* only for the starting tag... */
656 #define MAX_ATTR_COUNT 50
657 data1_termlist *tll[MAX_ATTR_COUNT];
661 /* get termlists for attributes, and find out, if we have to do xpath indexing */
662 for (xp = n->u.tag.attributes; xp; xp = xp->next) {
667 for (xp = n->u.tag.attributes; xp; xp = xp->next) {
669 int do_xpindex = 1 - termlist_only;
671 char attr_tag_path_full[1024];
674 /* this could be cached as well */
675 sprintf (attr_tag_path_full, "@%s/%.*s",
676 xp->name, int_len, tag_path_full);
678 tll[i] = xpath_termlist_by_tagpath(attr_tag_path_full,n);
680 /* if there is a ! in the xelm termlist, or default indexing is on,
681 proceed with xpath idx */
684 for (; tl; tl = tl->next)
693 /* attribute (no value) */
696 wrd->term_buf = xp->name;
697 wrd->term_len = strlen(xp->name);
703 strlen(xp->name) + strlen(xp->value) < sizeof(comb)-2) {
705 /* attribute value exact */
706 strcpy (comb, xp->name);
708 strcat (comb, xp->value);
712 wrd->term_buf = comb;
713 wrd->term_len = strlen(comb);
723 for (xp = n->u.tag.attributes; xp; xp = xp->next) {
725 char attr_tag_path_full[1024];
729 sprintf (attr_tag_path_full, "@%s/%.*s",
730 xp->name, int_len, tag_path_full);
734 /* If there is a termlist given (=xelm directive) */
735 for (; tl; tl = tl->next)
738 /* add xpath index for the attribute */
739 index_xpath_attr (attr_tag_path_full, xp->name,
740 xp->value, tl->structure,
744 /* add attribute based index for the attribute */
747 (tl->att->parent->reference);
748 wrd->attrUse = tl->att->locals->local;
749 wrd->reg_type = *tl->structure;
750 wrd->term_buf = xp->value;
751 wrd->term_len = strlen(xp->value);
757 /* if there was no termlist for the given path,
758 or the termlist didn't have a ! element, index
759 the attribute as "w" */
760 if ((!xpdone) && (!termlist_only))
762 index_xpath_attr (attr_tag_path_full, xp->name,
763 xp->value, "w", p, wrd);
772 static void index_termlist (struct source_parser *sp, data1_node *par,
774 struct recExtractCtrl *p, int level, RecWord *wrd)
776 data1_termlist *tlist = 0;
777 data1_datatype dtype = DATA1K_string;
780 * cycle up towards the root until we find a tag with an att..
781 * this has the effect of indexing locally defined tags with
782 * the attribute of their ancestor in the record.
785 while (!par->u.tag.element)
786 if (!par->parent || !(par=get_parent_tag(p->dh, par->parent)))
788 if (!par || !(tlist = par->u.tag.element->termlists))
790 if (par->u.tag.element->tag)
791 dtype = par->u.tag.element->tag->kind;
793 for (; tlist; tlist = tlist->next)
795 /* consider source */
797 assert(tlist->source);
798 sp_parse(sp, n, wrd, tlist->source);
800 if (wrd->term_buf && wrd->term_len)
802 if (p->flagShowRecords)
805 printf("%*sIdx: [%s]", (level + 1) * 4, "",
807 printf("%s:%s [%d] %s",
808 tlist->att->parent->name,
809 tlist->att->name, tlist->att->value,
811 printf (" XData:\"");
812 for (i = 0; i<wrd->term_len && i < 40; i++)
813 fputc (wrd->term_buf[i], stdout);
815 if (wrd->term_len > 40)
817 fputc ('\n', stdout);
821 wrd->reg_type = *tlist->structure;
822 wrd->attrSet = (int) (tlist->att->parent->reference);
823 wrd->attrUse = tlist->att->locals->local;
830 static int dumpkeys_r(struct source_parser *sp,
831 data1_node *n, struct recExtractCtrl *p, int level,
834 for (; n; n = n->next)
836 if (p->flagShowRecords) /* display element description to user */
838 if (n->which == DATA1N_root)
840 printf("%*s", level * 4, "");
841 printf("Record type: '%s'\n", n->u.root.type);
843 else if (n->which == DATA1N_tag)
847 printf("%*s", level * 4, "");
848 if (!(e = n->u.tag.element))
849 printf("Local tag: '%s'\n", n->u.tag.tag);
852 printf("Elm: '%s' ", e->name);
855 data1_tag *t = e->tag;
857 printf("TagNam: '%s' ", t->names->name);
860 printf("%s[%d],", t->tagset->name, t->tagset->type);
863 if (t->which == DATA1T_numeric)
864 printf("%d)", t->value.numeric);
866 printf("'%s')", t->value.string);
873 if (n->which == DATA1N_tag)
875 index_termlist(sp, n, n, p, level, wrd);
876 /* index start tag */
877 if (n->root->u.root.absyn)
878 index_xpath(sp, n, p, level, wrd, 1);
882 if (dumpkeys_r(sp, n->child, p, level + 1, wrd) < 0)
886 if (n->which == DATA1N_data)
888 data1_node *par = get_parent_tag(p->dh, n);
890 if (p->flagShowRecords)
892 printf("%*s", level * 4, "");
894 if (n->u.data.len > 256)
895 printf("'%.170s ... %.70s'\n", n->u.data.data,
896 n->u.data.data + n->u.data.len-70);
897 else if (n->u.data.len > 0)
898 printf("'%.*s'\n", n->u.data.len, n->u.data.data);
904 index_termlist(sp, par, n, p, level, wrd);
906 index_xpath(sp, n, p, level, wrd, 1016);
909 if (n->which == DATA1N_tag)
912 index_xpath(sp, n, p, level, wrd, 2);
915 if (p->flagShowRecords && n->which == DATA1N_root)
917 printf("%*s-------------\n\n", level * 4, "");
923 static int dumpkeys(data1_node *n, struct recExtractCtrl *p, RecWord *wrd)
925 struct source_parser *sp = source_parser_create();
926 int r = dumpkeys_r(sp, n, p, 0, wrd);
927 source_parser_destroy(sp);
931 int grs_extract_tree(struct recExtractCtrl *p, data1_node *n)
934 int oidtmp[OID_SIZE];
937 oe.proto = PROTO_Z3950;
938 oe.oclass = CLASS_SCHEMA;
941 oe.value = n->u.root.absyn->reference;
943 if ((oid_ent_to_oid (&oe, oidtmp)))
944 (*p->schemaAdd)(p, oidtmp);
948 return dumpkeys(n, p, &wrd);
951 static int grs_extract_sub(void *clientData, struct recExtractCtrl *p,
953 data1_node *(*grs_read)(struct grs_read_info *))
956 struct grs_read_info gri;
958 int oidtmp[OID_SIZE];
961 gri.readf = p->readf;
962 gri.seekf = p->seekf;
963 gri.tellf = p->tellf;
966 gri.offset = p->offset;
969 gri.clientData = clientData;
971 n = (*grs_read)(&gri);
973 return RECCTRL_EXTRACT_EOF;
974 oe.proto = PROTO_Z3950;
975 oe.oclass = CLASS_SCHEMA;
977 if (!n->u.root.absyn)
978 return RECCTRL_EXTRACT_ERROR;
982 oe.value = n->u.root.absyn->reference;
983 if ((oid_ent_to_oid (&oe, oidtmp)))
984 (*p->schemaAdd)(p, oidtmp);
986 data1_concat_text(p->dh, mem, n);
988 /* ensure our data1 tree is UTF-8 */
989 data1_iconv (p->dh, mem, n, "UTF-8", data1_get_encoding(p->dh, n));
992 data1_pr_tree (p->dh, n, stdout);
996 if (dumpkeys(n, p, &wrd) < 0)
998 data1_free_tree(p->dh, n);
999 return RECCTRL_EXTRACT_ERROR_GENERIC;
1001 data1_free_tree(p->dh, n);
1002 return RECCTRL_EXTRACT_OK;
1005 int zebra_grs_extract(void *clientData, struct recExtractCtrl *p,
1006 data1_node *(*grs_read)(struct grs_read_info *))
1009 NMEM mem = nmem_create ();
1010 ret = grs_extract_sub(clientData, p, mem, grs_read);
1016 * Return: -1: Nothing done. 0: Ok. >0: Bib-1 diagnostic.
1018 static int process_comp(data1_handle dh, data1_node *n, Z_RecordComposition *c,
1019 char **addinfo, ODR o)
1021 data1_esetname *eset;
1022 Z_Espec1 *espec = 0;
1027 case Z_RecordComp_simple:
1028 if (c->u.simple->which != Z_ElementSetNames_generic)
1029 return 26; /* only generic form supported. Fix this later */
1030 if (!(eset = data1_getesetbyname(dh, n->u.root.absyn,
1031 c->u.simple->u.generic)))
1033 yaz_log(YLOG_LOG, "Unknown esetname '%s'", c->u.simple->u.generic);
1034 *addinfo = odr_strdup(o, c->u.simple->u.generic);
1035 return 25; /* invalid esetname */
1037 yaz_log(YLOG_DEBUG, "Esetname '%s' in simple compspec",
1038 c->u.simple->u.generic);
1041 case Z_RecordComp_complex:
1042 if (c->u.complex->generic)
1044 /* insert check for schema */
1045 if ((p = c->u.complex->generic->elementSpec))
1049 case Z_ElementSpec_elementSetName:
1051 data1_getesetbyname(dh, n->u.root.absyn,
1052 p->u.elementSetName)))
1054 yaz_log(YLOG_DEBUG, "Unknown esetname '%s'",
1055 p->u.elementSetName);
1056 *addinfo = odr_strdup(o, p->u.elementSetName);
1057 return 25; /* invalid esetname */
1059 yaz_log(YLOG_DEBUG, "Esetname '%s' in complex compspec",
1060 p->u.elementSetName);
1063 case Z_ElementSpec_externalSpec:
1064 if (p->u.externalSpec->which == Z_External_espec1)
1066 yaz_log(YLOG_DEBUG, "Got Espec-1");
1067 espec = p->u.externalSpec-> u.espec1;
1071 yaz_log(YLOG_LOG, "Unknown external espec.");
1072 return 25; /* bad. what is proper diagnostic? */
1079 return 26; /* fix */
1083 yaz_log(YLOG_DEBUG, "Element: Espec-1 match");
1084 return data1_doespec1(dh, n, espec);
1088 yaz_log(YLOG_DEBUG, "Element: all match");
1093 /* Add Zebra info in separate namespace ...
1096 <metadata xmlns="http://www.indexdata.dk/zebra/">
1098 <localnumber>447</localnumber>
1099 <filename>records/genera.xml</filename>
1104 static void zebra_xml_metadata (struct recRetrieveCtrl *p, data1_node *top,
1107 const char *idzebra_ns[3];
1108 const char *i2 = "\n ";
1109 const char *i4 = "\n ";
1112 idzebra_ns[0] = "xmlns";
1113 idzebra_ns[1] = "http://www.indexdata.dk/zebra/";
1116 data1_mk_text (p->dh, mem, i2, top);
1118 n = data1_mk_tag (p->dh, mem, "idzebra", idzebra_ns, top);
1120 data1_mk_text (p->dh, mem, "\n", top);
1122 data1_mk_text (p->dh, mem, i4, n);
1124 data1_mk_tag_data_int (p->dh, n, "size", p->recordSize, mem);
1128 data1_mk_text (p->dh, mem, i4, n);
1129 data1_mk_tag_data_int (p->dh, n, "score", p->score, mem);
1131 data1_mk_text (p->dh, mem, i4, n);
1132 data1_mk_tag_data_zint (p->dh, n, "localnumber", p->localno, mem);
1135 data1_mk_text (p->dh, mem, i4, n);
1136 data1_mk_tag_data_text(p->dh, n, "filename", p->fname, mem);
1138 data1_mk_text (p->dh, mem, i2, n);
1141 int zebra_grs_retrieve(void *clientData, struct recRetrieveCtrl *p,
1142 data1_node *(*grs_read)(struct grs_read_info *))
1144 data1_node *node = 0, *onode = 0, *top;
1147 int res, selected = 0;
1149 struct grs_read_info gri;
1150 const char *tagname;
1152 int requested_schema = VAL_NONE;
1153 data1_marctab *marctab;
1156 mem = nmem_create();
1157 gri.readf = p->readf;
1158 gri.seekf = p->seekf;
1159 gri.tellf = p->tellf;
1165 gri.clientData = clientData;
1167 yaz_log(YLOG_DEBUG, "grs_retrieve");
1168 node = (*grs_read)(&gri);
1175 data1_concat_text(p->dh, mem, node);
1178 data1_pr_tree (p->dh, node, stdout);
1180 top = data1_get_root_tag (p->dh, node);
1182 yaz_log(YLOG_DEBUG, "grs_retrieve: size");
1183 tagname = data1_systag_lookup(node->u.root.absyn, "size", "size");
1185 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1187 dnew->u.data.what = DATA1I_text;
1188 dnew->u.data.data = dnew->lbuf;
1189 sprintf(dnew->u.data.data, "%d", p->recordSize);
1190 dnew->u.data.len = strlen(dnew->u.data.data);
1193 tagname = data1_systag_lookup(node->u.root.absyn, "rank", "rank");
1194 if (tagname && p->score >= 0 &&
1195 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1197 yaz_log(YLOG_DEBUG, "grs_retrieve: %s", tagname);
1198 dnew->u.data.what = DATA1I_num;
1199 dnew->u.data.data = dnew->lbuf;
1200 sprintf(dnew->u.data.data, "%d", p->score);
1201 dnew->u.data.len = strlen(dnew->u.data.data);
1204 tagname = data1_systag_lookup(node->u.root.absyn, "sysno",
1205 "localControlNumber");
1206 if (tagname && p->localno > 0 &&
1207 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1209 yaz_log(YLOG_DEBUG, "grs_retrieve: %s", tagname);
1210 dnew->u.data.what = DATA1I_text;
1211 dnew->u.data.data = dnew->lbuf;
1213 sprintf(dnew->u.data.data, ZINT_FORMAT, p->localno);
1214 dnew->u.data.len = strlen(dnew->u.data.data);
1217 if (p->input_format == VAL_TEXT_XML)
1218 zebra_xml_metadata (p, top, mem);
1221 data1_pr_tree (p->dh, node, stdout);
1223 if (p->comp && p->comp->which == Z_RecordComp_complex &&
1224 p->comp->u.complex->generic &&
1225 p->comp->u.complex->generic->which == Z_Schema_oid &&
1226 p->comp->u.complex->generic->schema.oid)
1228 oident *oe = oid_getentbyoid (p->comp->u.complex->generic->schema.oid);
1230 requested_schema = oe->value;
1232 /* If schema has been specified, map if possible, then check that
1233 * we got the right one
1235 if (requested_schema != VAL_NONE)
1237 yaz_log(YLOG_DEBUG, "grs_retrieve: schema mapping");
1238 for (map = node->u.root.absyn->maptabs; map; map = map->next)
1240 if (map->target_absyn_ref == requested_schema)
1243 if (!(node = data1_map_record(p->dh, onode, map, mem)))
1252 if (node->u.root.absyn &&
1253 requested_schema != node->u.root.absyn->reference)
1255 p->diagnostic = 238;
1261 * Does the requested format match a known syntax-mapping? (this reflects
1262 * the overlap of schema and formatting which is inherent in the MARC
1265 yaz_log(YLOG_DEBUG, "grs_retrieve: syntax mapping");
1266 if (node->u.root.absyn)
1267 for (map = node->u.root.absyn->maptabs; map; map = map->next)
1269 if (map->target_absyn_ref == p->input_format)
1272 if (!(node = data1_map_record(p->dh, onode, map, mem)))
1281 yaz_log(YLOG_DEBUG, "grs_retrieve: schemaIdentifier");
1282 if (node->u.root.absyn &&
1283 node->u.root.absyn->reference != VAL_NONE &&
1284 p->input_format == VAL_GRS1)
1288 int oidtmp[OID_SIZE];
1290 oe.proto = PROTO_Z3950;
1291 oe.oclass = CLASS_SCHEMA;
1292 oe.value = node->u.root.absyn->reference;
1294 if ((oid = oid_ent_to_oid (&oe, oidtmp)))
1297 data1_handle dh = p->dh;
1301 for (ii = oid; *ii >= 0; ii++)
1305 sprintf(p, "%d", *ii);
1308 if ((dnew = data1_mk_tag_data_wd(dh, top,
1309 "schemaIdentifier", mem)))
1311 dnew->u.data.what = DATA1I_oid;
1312 dnew->u.data.data = (char *) nmem_malloc(mem, p - tmp);
1313 memcpy(dnew->u.data.data, tmp, p - tmp);
1314 dnew->u.data.len = p - tmp;
1319 yaz_log(YLOG_DEBUG, "grs_retrieve: element spec");
1320 if (p->comp && (res = process_comp(p->dh, node, p->comp, &p->addinfo,
1323 p->diagnostic = res;
1325 data1_free_tree(p->dh, onode);
1326 data1_free_tree(p->dh, node);
1330 else if (p->comp && !res)
1334 data1_pr_tree (p->dh, node, stdout);
1336 yaz_log(YLOG_DEBUG, "grs_retrieve: transfer syntax mapping");
1337 switch (p->output_format = (p->input_format != VAL_NONE ?
1338 p->input_format : VAL_SUTRS))
1342 data1_pr_tree (p->dh, node, stdout);
1344 /* default output encoding for XML is UTF-8 */
1345 data1_iconv (p->dh, mem, node,
1346 p->encoding ? p->encoding : "UTF-8",
1347 data1_get_encoding(p->dh, node));
1349 if (!(p->rec_buf = data1_nodetoidsgml(p->dh, node, selected,
1351 p->diagnostic = 238;
1354 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1355 memcpy (new_buf, p->rec_buf, p->rec_len);
1356 p->rec_buf = new_buf;
1360 data1_iconv (p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1362 if (!(p->rec_buf = data1_nodetogr(p->dh, node, selected,
1364 p->diagnostic = 238; /* not available in requested syntax */
1366 p->rec_len = (size_t) (-1);
1369 /* ensure our data1 tree is UTF-8 */
1370 data1_iconv (p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1372 if (!(p->rec_buf = data1_nodetoexplain(p->dh, node, selected,
1374 p->diagnostic = 238;
1376 p->rec_len = (size_t) (-1);
1379 /* ensure our data1 tree is UTF-8 */
1380 data1_iconv (p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1381 if (!(p->rec_buf = data1_nodetosummary(p->dh, node, selected,
1383 p->diagnostic = 238;
1385 p->rec_len = (size_t) (-1);
1389 data1_iconv (p->dh, mem, node, p->encoding,
1390 data1_get_encoding(p->dh, node));
1391 if (!(p->rec_buf = data1_nodetobuf(p->dh, node, selected,
1393 p->diagnostic = 238;
1396 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1397 memcpy (new_buf, p->rec_buf, p->rec_len);
1398 p->rec_buf = new_buf;
1403 data1_iconv (p->dh, mem, node, p->encoding,
1404 data1_get_encoding(p->dh, node));
1405 if (!(p->rec_buf = data1_nodetosoif(p->dh, node, selected,
1407 p->diagnostic = 238;
1410 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1411 memcpy (new_buf, p->rec_buf, p->rec_len);
1412 p->rec_buf = new_buf;
1416 if (!node->u.root.absyn)
1418 p->diagnostic = 238;
1421 for (marctab = node->u.root.absyn->marc; marctab;
1422 marctab = marctab->next)
1423 if (marctab->reference == p->input_format)
1427 p->diagnostic = 238;
1431 data1_iconv (p->dh, mem, node, p->encoding,
1432 data1_get_encoding(p->dh, node));
1433 if (!(p->rec_buf = data1_nodetomarc(p->dh, marctab, node,
1434 selected, &p->rec_len)))
1435 p->diagnostic = 238;
1438 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1439 memcpy (new_buf, p->rec_buf, p->rec_len);
1440 p->rec_buf = new_buf;
1444 data1_free_tree(p->dh, node);
1446 data1_free_tree(p->dh, onode);