X-Git-Url: http://git.indexdata.com/?a=blobdiff_plain;f=recctrl%2Frecgrs.c;h=613e8e32a35b7bf34e93833daa257339891fe7de;hb=5e22c797a3b8155ec46e4680f2bc3b5ef163752b;hp=1e0c72a0000f7425ef959a1fb9a00651e229feba;hpb=03ecbe8fd92f9e55e07a21bc0486e3f78fcaa7cc;p=idzebra-moved-to-github.git diff --git a/recctrl/recgrs.c b/recctrl/recgrs.c index 1e0c72a..613e8e3 100644 --- a/recctrl/recgrs.c +++ b/recctrl/recgrs.c @@ -1,9 +1,24 @@ -/* - * Copyright (C) 1994-2002, Index Data - * All rights reserved. - * - * $Id: recgrs.c,v 1.53 2002-07-03 10:05:19 adam Exp $ - */ +/* $Id: recgrs.c,v 1.73 2003-02-18 11:57:58 adam Exp $ + Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002 + Index Data Aps + +This file is part of the Zebra server. + +Zebra is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +Zebra is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Zebra; see the file LICENSE.zebra. If not, write to the +Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. +*/ #include #include @@ -84,9 +99,12 @@ static void *grs_init(RecType recType) grs_add_handler (h, recTypeGrs_tcl); #endif grs_add_handler (h, recTypeGrs_marc); -#if YAZ_HAVE_EXPAT +#if HAVE_EXPAT_H grs_add_handler (h, recTypeGrs_xml); #endif +#if HAVE_PERL + grs_add_handler (h, recTypeGrs_perl); +#endif return h; } @@ -105,6 +123,189 @@ 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 + 3 start attr (and attr-exact) + 4 end attr + + 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, int level, RecWord *wrd, int use) { @@ -116,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) @@ -148,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; @@ -164,9 +407,96 @@ static void index_xpath (data1_node *n, struct recExtractCtrl *p, } else { - (*p->tokenAdd)(wrd); + data1_xattr *xp; + (*p->tokenAdd)(wrd); /* index element pag (AKA tag path) */ + if (use == 1) + { + for (xp = n->u.tag.attributes; xp; xp = xp->next) + { + char comb[512]; + /* attribute (no value) */ + wrd->reg_type = '0'; + wrd->attrUse = 3; + wrd->string = xp->name; + wrd->length = strlen(xp->name); + + wrd->seqno--; + (*p->tokenAdd)(wrd); + + if (xp->value && + strlen(xp->name) + strlen(xp->value) < sizeof(comb)-2) + { + /* attribute value exact */ + strcpy (comb, xp->name); + strcat (comb, "="); + strcat (comb, xp->value); + + wrd->attrUse = 3; + wrd->reg_type = '0'; + wrd->string = comb; + wrd->length = strlen(comb); + wrd->seqno--; + + (*p->tokenAdd)(wrd); + } + } + for (xp = n->u.tag.attributes; xp; xp = xp->next) + { + char attr_tag_path_full[1024]; + int int_len = flen; + + 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; + wrd->length = strlen(attr_tag_path_full); + (*p->tokenAdd)(wrd); + + if (xp->value) + { + /* the same jokes, as with the data nodes ... */ + data1_termlist *tl; + int xpdone = 0; + + wrd->string = xp->value; + wrd->length = strlen(xp->value); + 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; + wrd->length = strlen(attr_tag_path_full); + (*p->tokenAdd)(wrd); + } + } } - break; } } @@ -175,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 @@ -182,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; @@ -293,8 +625,12 @@ static int dumpkeys(data1_node *n, struct recExtractCtrl *p, int level, { index_termlist (n, n, p, level, wrd); /* index start tag */ + assert (n->root->u.root.absyn); + if (!n->root->u.root.absyn) index_xpath (n, p, level, wrd, 1); + else if (n->root->u.root.absyn->enable_xpath_indexing) + index_xpath (n, p, level, wrd, 1); } if (n->child) @@ -310,8 +646,8 @@ static int dumpkeys(data1_node *n, struct recExtractCtrl *p, int level, { printf("%*s", level * 4, ""); printf("Data: "); - if (n->u.data.len > 32) - printf("'%.24s ... %.6s'\n", n->u.data.data, + if (n->u.data.len > 256) + printf("'%.240s ... %.6s'\n", n->u.data.data, n->u.data.data + n->u.data.len-6); else if (n->u.data.len > 0) printf("'%.*s'\n", n->u.data.len, n->u.data.data); @@ -323,7 +659,8 @@ static int dumpkeys(data1_node *n, struct recExtractCtrl *p, int level, index_termlist (par, n, p, level, wrd); if (!n->root->u.root.absyn) index_xpath (n, p, level, wrd, 1016); - + else if (n->root->u.root.absyn->enable_xpath_indexing) + index_xpath (n, p, level, wrd, 1016); } if (n->which == DATA1N_tag) @@ -331,9 +668,10 @@ static int dumpkeys(data1_node *n, struct recExtractCtrl *p, int level, /* index end tag */ if (!n->root->u.root.absyn) index_xpath (n, p, level, wrd, 2); + else if (n->root->u.root.absyn->enable_xpath_indexing) + index_xpath (n, p, level, wrd, 2); } - if (p->flagShowRecords && n->which == DATA1N_root) { printf("%*s-------------\n\n", level * 4, ""); @@ -358,6 +696,7 @@ int grs_extract_tree(struct recExtractCtrl *p, data1_node *n) (*p->schemaAdd)(p, oidtmp); } (*p->init)(p, &wrd); + return dumpkeys(n, p, 0, &wrd); } @@ -380,7 +719,7 @@ static int grs_extract_sub(struct grs_handlers *h, struct recExtractCtrl *p, gri.dh = p->dh; if (read_grs_type (h, &gri, p->subType, &n)) - return RECCTRL_EXTRACT_ERROR; + return RECCTRL_EXTRACT_ERROR_NO_SUCH_FILTER; if (!n) return RECCTRL_EXTRACT_EOF; oe.proto = PROTO_Z3950; @@ -395,14 +734,19 @@ static int grs_extract_sub(struct grs_handlers *h, struct recExtractCtrl *p, if ((oid_ent_to_oid (&oe, oidtmp))) (*p->schemaAdd)(p, oidtmp); } + + /* ensure our data1 tree is UTF-8 */ + data1_iconv (p->dh, mem, n, "UTF-8", data1_get_encoding(p->dh, n)); + #if 0 data1_pr_tree (p->dh, n, stdout); #endif + (*p->init)(p, &wrd); if (dumpkeys(n, p, 0, &wrd) < 0) { data1_free_tree(p->dh, n); - return RECCTRL_EXTRACT_ERROR; + return RECCTRL_EXTRACT_ERROR_GENERIC; } data1_free_tree(p->dh, n); return RECCTRL_EXTRACT_OK; @@ -494,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) @@ -526,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; @@ -555,22 +923,27 @@ static int grs_retrieve(void *clientData, struct recRetrieveCtrl *p) nmem_destroy (mem); return 0; } + /* ensure our data1 tree is UTF-8 */ + data1_iconv (p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node)); + #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); @@ -580,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 @@ -679,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; @@ -712,9 +1095,15 @@ static int grs_retrieve(void *clientData, struct recRetrieveCtrl *p) switch (p->output_format = (p->input_format != VAL_NONE ? 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"); if (!(p->rec_buf = data1_nodetoidsgml(p->dh, node, selected, &p->rec_len))) @@ -749,6 +1138,8 @@ static int grs_retrieve(void *clientData, struct recRetrieveCtrl *p) p->rec_len = (size_t) (-1); break; case VAL_SUTRS: + if (p->encoding) + data1_iconv (p->dh, mem, node, p->encoding, "UTF-8"); if (!(p->rec_buf = data1_nodetobuf(p->dh, node, selected, &p->rec_len))) p->diagnostic = 238; @@ -785,6 +1176,8 @@ static int grs_retrieve(void *clientData, struct recRetrieveCtrl *p) p->diagnostic = 238; break; } + if (p->encoding) + data1_iconv (p->dh, mem, node, p->encoding, "UTF-8"); if (!(p->rec_buf = data1_nodetomarc(p->dh, marctab, node, selected, &p->rec_len))) p->diagnostic = 238;