X-Git-Url: http://git.indexdata.com/?a=blobdiff_plain;f=recctrl%2Frecgrs.c;h=a0cdef7c9a54e146f2b1f9f2cfff24a7301dd4ae;hb=9823f7a1e997efcb035afcaa26718b8b7f87fc0a;hp=0e44cf2c6a33e300e59b079f1227561768bd6d4f;hpb=37695f0ca9b5f0cc0bf1d55fb1b0a39a5e8bb486;p=idzebra-moved-to-github.git diff --git a/recctrl/recgrs.c b/recctrl/recgrs.c index 0e44cf2..a0cdef7 100644 --- a/recctrl/recgrs.c +++ b/recctrl/recgrs.c @@ -1,5 +1,5 @@ -/* $Id: recgrs.c,v 1.69 2002-11-15 21:57:41 adam Exp $ - Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002 +/* $Id: recgrs.c,v 1.75 2003-03-08 14:27:58 pop Exp $ + Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003 Index Data Aps This file is part of the Zebra server. @@ -123,6 +123,173 @@ static void grs_destroy(void *clientData) xfree (h); } +int d1_check_xpath_predicate(data1_node *n, struct xpath_predicate *p) { + int res = 1; + char *attname; + data1_xattr *attr; + + if (!p) { + return (1); + } else { + if (p->which == XPATH_PREDICATE_RELATION) { + if (p->u.relation.name[0]) { + if (*p->u.relation.name != '@') { + logf(LOG_WARN, + " Only attributes (@) are supported in xelm xpath predicates"); + logf(LOG_WARN, "predicate %s ignored", p->u.relation.name); + return (1); + } + attname = p->u.relation.name + 1; + res = 0; + /* looking for the attribute with a specified name */ + for (attr = n->u.tag.attributes; attr; attr = attr->next) { + logf(LOG_DEBUG," - attribute %s <-> %s", attname, attr->name ); + + if (!strcmp(attr->name, attname)) { + if (p->u.relation.op[0]) { + if (*p->u.relation.op != '=') { + logf(LOG_WARN, + "Only '=' relation is supported (%s)",p->u.relation.op); + logf(LOG_WARN, "predicate %s ignored", p->u.relation.name); + res = 1; break; + } else { + logf(LOG_DEBUG," - value %s <-> %s", + p->u.relation.value, attr->value ); + if (!strcmp(attr->value, p->u.relation.value)) { + res = 1; break; + } + } + } else { + /* attribute exists, no value specified */ + res = 1; break; + } + } + } + return (res); + } else { + return (1); + } + } + else if (p->which == XPATH_PREDICATE_BOOLEAN) { + if (!strcmp(p->u.boolean.op,"and")) { + return (d1_check_xpath_predicate(n, p->u.boolean.left) + && d1_check_xpath_predicate(n, p->u.boolean.right)); + } + else if (!strcmp(p->u.boolean.op,"or")) { + return (d1_check_xpath_predicate(n, p->u.boolean.left) + || d1_check_xpath_predicate(n, p->u.boolean.right)); + } else { + logf(LOG_WARN, "Unknown boolean relation %s, ignored",p->u.boolean.op); + return (1); + } + } + } + return 0; +} + + +/* *ostrich* + + New function, looking for xpath "element" definitions in abs, by + tagpath, using a kind of ugly regxp search.The DFA was built while + parsing abs, so here we just go trough them and try to match + against the given tagpath. The first matching entry is returned. + + pop, 2002-12-13 + + Added support for enhanced xelm. Now [] predicates are considered + as well, when selecting indexing rules... (why the hell it's called + termlist???) + + pop, 2003-01-17 + + */ + +data1_termlist *xpath_termlist_by_tagpath(char *tagpath, data1_node *n) +{ + data1_absyn *abs = n->root->u.root.absyn; + data1_xpelement *xpe = abs->xp_elements; + data1_node *nn; +#ifdef ENHANCED_XELM + struct xpath_location_step *xp; + +#endif + char *pexpr = xmalloc(strlen(tagpath)+2); + int ok = 0; + + sprintf (pexpr, "%s\n", tagpath); + while (xpe) + { + struct DFA_state **dfaar = xpe->dfa->states; + struct DFA_state *s=dfaar[0]; + struct DFA_tran *t; + const char *p; + int i; + unsigned char c; + int start_line = 1; + + c = *pexpr++; t = s->trans; i = s->tran_no; + if (c >= t->ch[0] && c <= t->ch[1]) { + p = pexpr; + do { + if ((s = dfaar[t->to])->rule_no && + (start_line || s->rule_nno)) { + ok = 1; + break; + } + for (t=s->trans, i=s->tran_no; --i >= 0; t++) { + if ((unsigned) *p >= t->ch[0] && (unsigned) *p <= t->ch[1]) + break; + } + p++; + } while (i >= 0); + } + pexpr--; + if (ok) { +#ifdef ENHANCED_XELM + /* we have to check the perdicates up to the root node */ + xp = xpe->xpath; + + /* find the first tag up in the node structure */ + nn = n; while (nn && nn->which != DATA1N_tag) { + nn = nn->parent; + } + + /* go from inside out in the node structure, while going + backwards trough xpath location steps ... */ + for (i=xpe->xpath_len - 1; i>0; i--) { + + logf(LOG_DEBUG,"Checking step %d: %s on tag %s", + i,xp[i].part,nn->u.tag.tag); + + if (!d1_check_xpath_predicate(nn, xp[i].predicate)) { + logf(LOG_DEBUG," Predicates didn't match"); + ok = 0; + break; + } + + if (nn->which == DATA1N_tag) { + nn = nn->parent; + } + } +#endif + if (ok) { + break; + } + } + xpe = xpe->next; + } + + xfree(pexpr); + + if (ok) { + logf(LOG_DEBUG,"Got it"); + return xpe->termlists; + } else { + return NULL; + } +} + /* use 1 start element (tag) 2 end element @@ -131,6 +298,14 @@ static void grs_destroy(void *clientData) 1016 cdata 1015 attr data + + *ostrich* + + Now, if there is a matching xelm described in abs, for the + indexed element or the attribute, then the data is handled according + to those definitions... + + modified by pop, 2002-12-13 */ static void index_xpath (data1_node *n, struct recExtractCtrl *p, @@ -144,24 +319,64 @@ static void index_xpath (data1_node *n, struct recExtractCtrl *p, switch (n->which) { case DATA1N_data: - wrd->reg_type = 'w'; wrd->string = n->u.data.data; wrd->length = n->u.data.len; - wrd->attrSet = VAL_IDXPATH, - wrd->attrUse = use; if (p->flagShowRecords) { printf("%*s data=", (level + 1) * 4, ""); for (i = 0; ilength && i < 8; i++) fputc (wrd->string[i], stdout); printf("\n"); - } - else - { - (*p->tokenAdd)(wrd); + } + else { + data1_termlist *tl; + int xpdone = 0; + flen = 0; + + /* we have to fetch the whole path to the data tag */ + for (nn = n; nn; nn = nn->parent) { + if (nn->which == DATA1N_tag) { + size_t tlen = strlen(nn->u.tag.tag); + if (tlen + flen > (sizeof(tag_path_full)-2)) return; + memcpy (tag_path_full + flen, nn->u.tag.tag, tlen); + flen += tlen; + tag_path_full[flen++] = '/'; + } + else if (nn->which == DATA1N_root) break; + } + + tag_path_full[flen] = 0; + + /* If we have a matching termlist... */ + if ((tl = xpath_termlist_by_tagpath(tag_path_full, n))) { + for (; tl; tl = tl->next) { + wrd->reg_type = *tl->structure; + /* this is the ! case, so structure is for the xpath index */ + if (!tl->att) { + wrd->attrSet = VAL_IDXPATH; + wrd->attrUse = use; + (*p->tokenAdd)(wrd); + xpdone = 1; + /* this is just the old fashioned attribute based index */ + } else { + wrd->attrSet = (int) (tl->att->parent->reference); + wrd->attrUse = tl->att->locals->local; + (*p->tokenAdd)(wrd); + } + } + } + /* xpath indexing is done, if there was no termlist given, + or no ! attribute... */ + if (!xpdone) { + wrd->attrSet = VAL_IDXPATH; + wrd->attrUse = use; + wrd->reg_type = 'w'; + (*p->tokenAdd)(wrd); + } } break; case DATA1N_tag: + flen = 0; for (nn = n; nn; nn = nn->parent) { if (nn->which == DATA1N_tag) @@ -176,6 +391,8 @@ static void index_xpath (data1_node *n, struct recExtractCtrl *p, else if (nn->which == DATA1N_root) break; } + + wrd->reg_type = '0'; wrd->string = tag_path_full; wrd->length = flen; @@ -232,7 +449,6 @@ static void index_xpath (data1_node *n, struct recExtractCtrl *p, sprintf (attr_tag_path_full, "@%s/%.*s", xp->name, int_len, tag_path_full); - wrd->reg_type = '0'; wrd->attrUse = 1; wrd->string = attr_tag_path_full; @@ -241,13 +457,40 @@ static void index_xpath (data1_node *n, struct recExtractCtrl *p, if (xp->value) { - wrd->attrUse = 1015; - wrd->reg_type = 'w'; + /* the same jokes, as with the data nodes ... */ + data1_termlist *tl; + int xpdone = 0; + wrd->string = xp->value; wrd->length = strlen(xp->value); - (*p->tokenAdd)(wrd); + wrd->reg_type = 'w'; + + if ((tl = xpath_termlist_by_tagpath(attr_tag_path_full, + n))) { + for (; tl; tl = tl->next) { + wrd->reg_type = *tl->structure; + if (!tl->att) { + wrd->attrSet = VAL_IDXPATH; + wrd->attrUse = 1015; + (*p->tokenAdd)(wrd); + xpdone = 1; + } else { + wrd->attrSet = (int) (tl->att->parent->reference); + wrd->attrUse = tl->att->locals->local; + (*p->tokenAdd)(wrd); + } + } + + } + if (!xpdone) { + wrd->attrSet = VAL_IDXPATH; + wrd->attrUse = 1015; + wrd->reg_type = 'w'; + (*p->tokenAdd)(wrd); + } } + wrd->attrSet = VAL_IDXPATH; wrd->reg_type = '0'; wrd->attrUse = 2; wrd->string = attr_tag_path_full; @@ -264,6 +507,7 @@ static void index_termlist (data1_node *par, data1_node *n, { data1_termlist *tlist = 0; data1_datatype dtype = DATA1K_string; + /* * cycle up towards the root until we find a tag with an att.. * this has the effect of indexing locally defined tags with @@ -271,19 +515,20 @@ static void index_termlist (data1_node *par, data1_node *n, */ while (!par->u.tag.element) - if (!par->parent || !(par=get_parent_tag(p->dh, par->parent))) - break; + if (!par->parent || !(par=get_parent_tag(p->dh, par->parent))) + break; if (!par || !(tlist = par->u.tag.element->termlists)) - return; + return; if (par->u.tag.element->tag) - dtype = par->u.tag.element->tag->kind; + dtype = par->u.tag.element->tag->kind; for (; tlist; tlist = tlist->next) { + char xattr[512]; /* consider source */ wrd->string = 0; - + if (!strcmp (tlist->source, "data") && n->which == DATA1N_data) { wrd->string = n->u.data.data; @@ -651,7 +896,7 @@ static int grs_retrieve(void *clientData, struct recRetrieveCtrl *p) int res, selected = 0; NMEM mem; struct grs_read_info gri; - char *tagname; + const char *tagname; struct grs_handlers *h = (struct grs_handlers *) clientData; int requested_schema = VAL_NONE; data1_marctab *marctab; @@ -689,16 +934,18 @@ static int grs_retrieve(void *clientData, struct recRetrieveCtrl *p) top = data1_get_root_tag (p->dh, node); logf (LOG_DEBUG, "grs_retrieve: size"); - if ((dnew = data1_mk_tag_data_wd(p->dh, top, "size", mem))) + tagname = data1_systag_lookup(node->u.root.absyn, "size", "size"); + if (tagname && + (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem))) { dnew->u.data.what = DATA1I_text; dnew->u.data.data = dnew->lbuf; sprintf(dnew->u.data.data, "%d", p->recordSize); dnew->u.data.len = strlen(dnew->u.data.data); } - - tagname = res_get_def(p->res, "tagrank", "rank"); - if (strcmp(tagname, "0") && p->score >= 0 && + + tagname = data1_systag_lookup(node->u.root.absyn, "rank", "rank"); + if (tagname && p->score >= 0 && (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem))) { logf (LOG_DEBUG, "grs_retrieve: %s", tagname); @@ -708,28 +955,40 @@ static int grs_retrieve(void *clientData, struct recRetrieveCtrl *p) dnew->u.data.len = strlen(dnew->u.data.data); } - tagname = res_get_def(p->res, "tagsysno", "localControlNumber"); - if (strcmp(tagname, "0") && p->localno > 0 && - (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem))) + tagname = data1_systag_lookup(node->u.root.absyn, "sysno", + "localControlNumber"); + if (tagname && p->localno > 0 && + (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem))) { logf (LOG_DEBUG, "grs_retrieve: %s", tagname); dnew->u.data.what = DATA1I_text; dnew->u.data.data = dnew->lbuf; - + sprintf(dnew->u.data.data, "%d", p->localno); dnew->u.data.len = strlen(dnew->u.data.data); } #if 0 data1_pr_tree (p->dh, node, stdout); #endif +#if YAZ_VERSIONL >= 0x010903L if (p->comp && p->comp->which == Z_RecordComp_complex && p->comp->u.complex->generic && - p->comp->u.complex->generic->schema) + p->comp->u.complex->generic->which == Z_Schema_oid && + p->comp->u.complex->generic->schema.oid) + { + oident *oe = oid_getentbyoid (p->comp->u.complex->generic->schema.oid); + if (oe) + requested_schema = oe->value; + } +#else + if (p->comp && p->comp->which == Z_RecordComp_complex && + p->comp->u.complex->generic && p->comp->u.complex->generic->schema) { oident *oe = oid_getentbyoid (p->comp->u.complex->generic->schema); if (oe) requested_schema = oe->value; } +#endif /* If schema has been specified, map if possible, then check that * we got the right one