X-Git-Url: http://git.indexdata.com/?a=blobdiff_plain;f=recctrl%2Frecgrs.c;h=c024bd41e9759944fea21b6f2ce1ac932506fe27;hb=5501453af5f35ea671edc7186f9959d0421fa58d;hp=12ad348bce02d3287c785a54fbbd48f1bdff7bc8;hpb=4ed19ee90fcd394f986d52c10ecf866888abc729;p=idzebra-moved-to-github.git diff --git a/recctrl/recgrs.c b/recctrl/recgrs.c index 12ad348..c024bd4 100644 --- a/recctrl/recgrs.c +++ b/recctrl/recgrs.c @@ -1,5 +1,5 @@ -/* $Id: recgrs.c,v 1.64 2002-08-29 15:10:47 adam Exp $ - Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002 +/* $Id: recgrs.c,v 1.74 2003-02-20 21:13:37 adam Exp $ + Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003 Index Data Aps This file is part of the Zebra server. @@ -102,6 +102,9 @@ static void *grs_init(RecType recType) #if HAVE_EXPAT_H grs_add_handler (h, recTypeGrs_xml); #endif +#if HAVE_PERL + grs_add_handler (h, recTypeGrs_perl); +#endif return h; } @@ -120,6 +123,171 @@ 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 = malloc(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; + } + + if (ok) { + logf(LOG_DEBUG,"Got it"); + return xpe->termlists; + } else { + return NULL; + } +} + /* use 1 start element (tag) 2 end element @@ -128,6 +296,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, @@ -141,24 +317,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) @@ -173,6 +389,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; @@ -229,7 +447,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; @@ -238,13 +455,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; @@ -261,6 +505,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 @@ -268,19 +513,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; @@ -592,28 +838,52 @@ static int process_comp(data1_handle dh, data1_node *n, Z_RecordComposition *c) } } -static void add_idzebra_info (struct recRetrieveCtrl *p, data1_node *top, - NMEM mem) +/* Add Zebra info in separate namespace ... + + 359 + 447 + records/genera.xml + + +*/ + +static void zebra_xml_metadata (struct recRetrieveCtrl *p, data1_node *top, + NMEM mem) { - const char *idzebra_ns[7]; + const char *idzebra_ns[3]; + const char *i2 = "\n "; + const char *i4 = "\n "; + data1_node *n; - idzebra_ns[0] = "xmlns:idzebra"; + idzebra_ns[0] = "xmlns"; idzebra_ns[1] = "http://www.indexdata.dk/zebra/"; idzebra_ns[2] = 0; - data1_tag_add_attr (p->dh, mem, top, idzebra_ns); + data1_mk_text (p->dh, mem, i2, top); - data1_mk_tag_data_int (p->dh, top, "idzebra:size", p->recordSize, - mem); - if (p->score != -1) - data1_mk_tag_data_int (p->dh, top, "idzebra:score", - p->score, mem); + n = data1_mk_tag (p->dh, mem, "idzebra", idzebra_ns, top); + + data1_mk_text (p->dh, mem, "\n", top); + + data1_mk_text (p->dh, mem, i4, n); - data1_mk_tag_data_int (p->dh, top, "idzebra:localnumber", p->localno, - mem); + data1_mk_tag_data_int (p->dh, n, "size", p->recordSize, mem); + + if (p->score != -1) + { + data1_mk_text (p->dh, mem, i4, n); + data1_mk_tag_data_int (p->dh, n, "score", p->score, mem); + } + data1_mk_text (p->dh, mem, i4, n); + data1_mk_tag_data_int (p->dh, n, "localnumber", p->localno, mem); if (p->fname) - data1_mk_tag_data_text(p->dh, top, "idzebra:filename", - p->fname, mem); + { + data1_mk_text (p->dh, mem, i4, n); + data1_mk_tag_data_text(p->dh, n, "filename", p->fname, mem); + } + data1_mk_text (p->dh, mem, i2, n); } static int grs_retrieve(void *clientData, struct recRetrieveCtrl *p) @@ -624,7 +894,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; @@ -656,22 +926,24 @@ static int grs_retrieve(void *clientData, struct recRetrieveCtrl *p) /* ensure our data1 tree is UTF-8 */ data1_iconv (p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node)); -#if 1 +#if 0 data1_pr_tree (p->dh, node, stdout); #endif 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); @@ -681,28 +953,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 @@ -780,9 +1064,7 @@ static int grs_retrieve(void *clientData, struct recRetrieveCtrl *p) sprintf(p, "%d", *ii); p += strlen(p); } - *(p++) = '\0'; - - if ((dnew = data1_mk_tag_data_wd(dh, node, + if ((dnew = data1_mk_tag_data_wd(dh, top, "schemaIdentifier", mem))) { dnew->u.data.what = DATA1I_oid; @@ -814,7 +1096,11 @@ static int grs_retrieve(void *clientData, struct recRetrieveCtrl *p) p->input_format : VAL_SUTRS)) { case VAL_TEXT_XML: - add_idzebra_info (p, top, mem); + zebra_xml_metadata (p, top, mem); + +#if 0 + data1_pr_tree (p->dh, node, stdout); +#endif if (p->encoding) data1_iconv (p->dh, mem, node, p->encoding, "UTF-8");