1 /* $Id: recgrs.c,v 1.89 2004-08-24 14:29:09 adam Exp $
2 Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004
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>
36 #define GRS_MAX_WORD 512
42 struct grs_handler *next;
46 struct grs_handler *handlers;
49 static int read_grs_type (struct grs_handlers *h,
50 struct grs_read_info *p, const char *type,
53 struct grs_handler *gh = h->handlers;
54 const char *cp = strchr (type, '.');
56 if (cp == NULL || cp == type)
58 cp = strlen(type) + type;
62 strcpy (p->type, cp+1);
63 for (gh = h->handlers; gh; gh = gh->next)
65 if (!memcmp (type, gh->type->type, cp-type) &&
66 gh->type->type[cp-type] == '\0')
71 gh->clientData = (*gh->type->init)();
73 p->clientData = gh->clientData;
74 *root = (gh->type->read)(p);
75 gh->clientData = p->clientData;
82 static void grs_add_handler (struct grs_handlers *h, RecTypeGrs t)
84 struct grs_handler *gh = (struct grs_handler *) xmalloc (sizeof(*gh));
85 gh->next = h->handlers;
92 static void *grs_init(RecType recType)
94 struct grs_handlers *h = (struct grs_handlers *) xmalloc (sizeof(*h));
97 grs_add_handler (h, recTypeGrs_sgml);
98 grs_add_handler (h, recTypeGrs_regx);
100 grs_add_handler (h, recTypeGrs_tcl);
102 grs_add_handler (h, recTypeGrs_marc);
103 grs_add_handler (h, recTypeGrs_marcxml);
105 grs_add_handler (h, recTypeGrs_xml);
108 grs_add_handler (h, recTypeGrs_perl);
110 grs_add_handler (h, recTypeGrs_danbib);
114 static void grs_destroy(void *clientData)
116 struct grs_handlers *h = (struct grs_handlers *) clientData;
117 struct grs_handler *gh = h->handlers, *gh_next;
122 (*gh->type->destroy)(gh->clientData);
129 struct source_parser {
136 static int sp_lex(struct source_parser *sp)
138 while (*sp->src == ' ')
142 while (*sp->src && !strchr("<>();,-: ", *sp->src))
151 sp->lookahead = *sp->src;
155 return sp->lookahead;
159 static int sp_expr(struct source_parser *sp, data1_node *n, RecWord *wrd)
161 if (sp->lookahead != 't')
163 if (sp->len == 4 && !memcmp(sp->tok, "data", sp->len))
165 if (n->which == DATA1N_data)
167 wrd->string = n->u.data.data;
168 wrd->length = n->u.data.len;
172 else if (sp->len == 3 && !memcmp(sp->tok, "tag", sp->len))
174 if (n->which == DATA1N_tag)
176 wrd->string = n->u.tag.tag;
177 wrd->length = strlen(n->u.tag.tag);
181 else if (sp->len == 4 && !memcmp(sp->tok, "attr", sp->len))
184 if (sp->lookahead != '(')
187 if (sp->lookahead != 't')
190 if (n->which == DATA1N_tag)
192 data1_xattr *p = n->u.tag.attributes;
193 while (p && strlen(p->name) != sp->len &&
194 memcmp (p->name, sp->tok, sp->len))
198 wrd->string = p->value;
199 wrd->length = strlen(p->value);
203 if (sp->lookahead != ')')
207 else if (sp->len == 5 && !memcmp(sp->tok, "range", sp->len))
211 if (sp->lookahead != '(')
216 if (sp->lookahead != ',')
220 if (sp->lookahead != 't')
222 start = atoi_n(sp->tok, sp->len);
225 if (sp->lookahead != ',')
229 if (sp->lookahead != 't')
231 len = atoi_n(sp->tok, sp->len);
234 if (sp->lookahead != ')')
238 if (wrd->string && wrd->length)
240 wrd->string += start;
241 wrd->length -= start;
242 if (wrd->length > len)
249 static int sp_parse(data1_node *n, RecWord *wrd, const char *src)
251 struct source_parser sp;
258 return sp_expr(&sp, n, wrd);
261 int d1_check_xpath_predicate(data1_node *n, struct xpath_predicate *p)
270 if (p->which == XPATH_PREDICATE_RELATION) {
271 if (p->u.relation.name[0]) {
272 if (*p->u.relation.name != '@') {
274 " Only attributes (@) are supported in xelm xpath predicates");
275 yaz_log(LOG_WARN, "predicate %s ignored", p->u.relation.name);
278 attname = p->u.relation.name + 1;
280 /* looking for the attribute with a specified name */
281 for (attr = n->u.tag.attributes; attr; attr = attr->next) {
282 yaz_log(LOG_DEBUG," - attribute %s <-> %s", attname, attr->name );
284 if (!strcmp(attr->name, attname)) {
285 if (p->u.relation.op[0]) {
286 if (*p->u.relation.op != '=') {
288 "Only '=' relation is supported (%s)",p->u.relation.op);
289 yaz_log(LOG_WARN, "predicate %s ignored", p->u.relation.name);
292 yaz_log(LOG_DEBUG," - value %s <-> %s",
293 p->u.relation.value, attr->value );
294 if (!strcmp(attr->value, p->u.relation.value)) {
299 /* attribute exists, no value specified */
304 yaz_log(LOG_DEBUG, "return %d", res);
310 else if (p->which == XPATH_PREDICATE_BOOLEAN) {
311 if (!strcmp(p->u.boolean.op,"and")) {
312 return d1_check_xpath_predicate(n, p->u.boolean.left)
313 && d1_check_xpath_predicate(n, p->u.boolean.right);
315 else if (!strcmp(p->u.boolean.op,"or")) {
316 return (d1_check_xpath_predicate(n, p->u.boolean.left)
317 || d1_check_xpath_predicate(n, p->u.boolean.right));
319 yaz_log(LOG_WARN, "Unknown boolean relation %s, ignored",p->u.boolean.op);
330 New function, looking for xpath "element" definitions in abs, by
331 tagpath, using a kind of ugly regxp search.The DFA was built while
332 parsing abs, so here we just go trough them and try to match
333 against the given tagpath. The first matching entry is returned.
337 Added support for enhanced xelm. Now [] predicates are considered
338 as well, when selecting indexing rules... (why the hell it's called
345 data1_termlist *xpath_termlist_by_tagpath(char *tagpath, data1_node *n)
347 data1_absyn *abs = n->root->u.root.absyn;
348 data1_xpelement *xpe = abs->xp_elements;
351 struct xpath_location_step *xp;
354 char *pexpr = xmalloc(strlen(tagpath)+2);
357 sprintf (pexpr, "%s\n", tagpath);
358 yaz_log(LOG_DEBUG,"Checking tagpath %s",tagpath);
361 struct DFA_state **dfaar = xpe->dfa->states;
362 struct DFA_state *s=dfaar[0];
369 c = *pexpr++; t = s->trans; i = s->tran_no;
370 if ((c >= t->ch[0] && c <= t->ch[1]) || (!t->ch[0])) {
373 if ((s = dfaar[t->to])->rule_no &&
374 (start_line || s->rule_nno)) {
378 for (t=s->trans, i=s->tran_no; --i >= 0; t++) {
379 if ((unsigned) *p >= t->ch[0] && (unsigned) *p <= t->ch[1])
386 yaz_log(LOG_DEBUG," xpath match %s",xpe->xpath_expr);
388 yaz_log(LOG_DEBUG," xpath no match %s",xpe->xpath_expr);
393 /* we have to check the perdicates up to the root node */
396 /* find the first tag up in the node structure */
397 nn = n; while (nn && nn->which != DATA1N_tag) {
401 /* go from inside out in the node structure, while going
402 backwards trough xpath location steps ... */
403 for (i=xpe->xpath_len - 1; i>0; i--) {
405 yaz_log(LOG_DEBUG,"Checking step %d: %s on tag %s",
406 i,xp[i].part,nn->u.tag.tag);
408 if (!d1_check_xpath_predicate(nn, xp[i].predicate)) {
409 yaz_log(LOG_DEBUG," Predicates didn't match");
414 if (nn->which == DATA1N_tag) {
429 yaz_log(LOG_DEBUG,"Got it");
430 return xpe->termlists;
437 1 start element (tag)
439 3 start attr (and attr-exact)
447 Now, if there is a matching xelm described in abs, for the
448 indexed element or the attribute, then the data is handled according
449 to those definitions...
451 modified by pop, 2002-12-13
454 /* add xpath index for an attribute */
455 static void index_xpath_attr (char *tag_path, char *name, char *value,
456 char *structure, struct recExtractCtrl *p,
459 wrd->attrSet = VAL_IDXPATH;
462 wrd->string = tag_path;
463 wrd->length = strlen(tag_path);
470 wrd->length = strlen(value);
476 wrd->string = tag_path;
477 wrd->length = strlen(tag_path);
482 static void index_xpath (data1_node *n, struct recExtractCtrl *p,
483 int level, RecWord *wrd, int use)
486 char tag_path_full[1024];
489 int termlist_only = 1;
493 yaz_log(LOG_DEBUG, "index_xpath level=%d use=%d", level, use);
494 if ((!n->root->u.root.absyn) ||
495 (n->root->u.root.absyn->enable_xpath_indexing)) {
502 wrd->string = n->u.data.data;
503 wrd->length = n->u.data.len;
507 /* we have to fetch the whole path to the data tag */
508 for (nn = n; nn; nn = nn->parent) {
509 if (nn->which == DATA1N_tag) {
510 size_t tlen = strlen(nn->u.tag.tag);
511 if (tlen + flen > (sizeof(tag_path_full)-2)) return;
512 memcpy (tag_path_full + flen, nn->u.tag.tag, tlen);
514 tag_path_full[flen++] = '/';
516 else if (nn->which == DATA1N_root) break;
519 tag_path_full[flen] = 0;
521 /* If we have a matching termlist... */
522 if (n->root->u.root.absyn &&
523 (tl = xpath_termlist_by_tagpath(tag_path_full, n)))
525 for (; tl; tl = tl->next)
527 /* need to copy recword because it may be changed */
529 wrd->reg_type = *tl->structure;
530 /* this is the ! case, so structure is for the xpath index */
531 memcpy (&wrd_tl, wrd, sizeof(*wrd));
533 sp_parse(n, &wrd_tl, tl->source);
535 wrd_tl.attrSet = VAL_IDXPATH;
536 wrd_tl.attrUse = use;
537 if (p->flagShowRecords)
540 printf("%*sXPath index", (level + 1) * 4, "");
541 printf (" XData:\"");
542 for (i = 0; i<wrd_tl.length && i < 40; i++)
543 fputc (wrd_tl.string[i], stdout);
545 if (wrd_tl.length > 40)
547 fputc ('\n', stdout);
550 (*p->tokenAdd)(&wrd_tl);
553 /* this is just the old fashioned attribute based index */
554 wrd_tl.attrSet = (int) (tl->att->parent->reference);
555 wrd_tl.attrUse = tl->att->locals->local;
556 if (p->flagShowRecords)
559 printf("%*sIdx: [%s]", (level + 1) * 4, "",
561 printf("%s:%s [%d] %s",
562 tl->att->parent->name,
563 tl->att->name, tl->att->value,
565 printf (" XData:\"");
566 for (i = 0; i<wrd_tl.length && i < 40; i++)
567 fputc (wrd_tl.string[i], stdout);
569 if (wrd_tl.length > 40)
571 fputc ('\n', stdout);
574 (*p->tokenAdd)(&wrd_tl);
578 /* xpath indexing is done, if there was no termlist given,
579 or no ! in the termlist, and default indexing is enabled... */
580 if (!p->flagShowRecords && !xpdone && !termlist_only)
582 wrd->attrSet = VAL_IDXPATH;
590 for (nn = n; nn; nn = nn->parent)
592 if (nn->which == DATA1N_tag)
594 size_t tlen = strlen(nn->u.tag.tag);
595 if (tlen + flen > (sizeof(tag_path_full)-2))
597 memcpy (tag_path_full + flen, nn->u.tag.tag, tlen);
599 tag_path_full[flen++] = '/';
601 else if (nn->which == DATA1N_root)
607 wrd->string = tag_path_full;
609 wrd->attrSet = VAL_IDXPATH;
611 if (p->flagShowRecords)
613 printf("%*s tag=", (level + 1) * 4, "");
614 for (i = 0; i<wrd->length && i < 40; i++)
615 fputc (wrd->string[i], stdout);
626 tag_path_full[flen] = 0;
628 /* Add tag start/end xpath index, only when there is a ! in the apropriate xelm
629 directive, or default xpath indexing is enabled */
630 if (!(do_xpindex = 1 - termlist_only)) {
631 if ((tl = xpath_termlist_by_tagpath(tag_path_full, n))) {
632 for (; tl; tl = tl->next) { if (!tl->att) {do_xpindex = 1;} }
636 (*p->tokenAdd)(wrd); /* index element pag (AKA tag path) */
639 if (use == 1) /* only for the starting tag... */
641 #define MAX_ATTR_COUNT 50
642 data1_termlist *tll[MAX_ATTR_COUNT];
646 /* get termlists for attributes, and find out, if we have to do xpath indexing */
647 for (xp = n->u.tag.attributes; xp; xp = xp->next) {
652 for (xp = n->u.tag.attributes; xp; xp = xp->next) {
654 int do_xpindex = 1 - termlist_only;
656 char attr_tag_path_full[1024];
659 /* this could be cached as well */
660 sprintf (attr_tag_path_full, "@%s/%.*s",
661 xp->name, int_len, tag_path_full);
663 tll[i] = xpath_termlist_by_tagpath(attr_tag_path_full,n);
665 /* if there is a ! in the xelm termlist, or default indexing is on,
666 proceed with xpath idx */
669 for (; tl; tl = tl->next)
678 /* attribute (no value) */
681 wrd->string = xp->name;
682 wrd->length = strlen(xp->name);
688 strlen(xp->name) + strlen(xp->value) < sizeof(comb)-2) {
690 /* attribute value exact */
691 strcpy (comb, xp->name);
693 strcat (comb, xp->value);
698 wrd->length = strlen(comb);
708 for (xp = n->u.tag.attributes; xp; xp = xp->next) {
710 char attr_tag_path_full[1024];
714 sprintf (attr_tag_path_full, "@%s/%.*s",
715 xp->name, int_len, tag_path_full);
719 /* If there is a termlist given (=xelm directive) */
720 for (; tl; tl = tl->next)
723 /* add xpath index for the attribute */
724 index_xpath_attr (attr_tag_path_full, xp->name,
725 xp->value, tl->structure,
729 /* add attribute based index for the attribute */
732 (tl->att->parent->reference);
733 wrd->attrUse = tl->att->locals->local;
734 wrd->reg_type = *tl->structure;
735 wrd->string = xp->value;
736 wrd->length = strlen(xp->value);
742 /* if there was no termlist for the given path,
743 or the termlist didn't have a ! element, index
744 the attribute as "w" */
745 if ((!xpdone) && (!termlist_only))
747 index_xpath_attr (attr_tag_path_full, xp->name,
748 xp->value, "w", p, wrd);
757 static void index_termlist (data1_node *par, data1_node *n,
758 struct recExtractCtrl *p, int level, RecWord *wrd)
760 data1_termlist *tlist = 0;
761 data1_datatype dtype = DATA1K_string;
764 * cycle up towards the root until we find a tag with an att..
765 * this has the effect of indexing locally defined tags with
766 * the attribute of their ancestor in the record.
769 while (!par->u.tag.element)
770 if (!par->parent || !(par=get_parent_tag(p->dh, par->parent)))
772 if (!par || !(tlist = par->u.tag.element->termlists))
774 if (par->u.tag.element->tag)
775 dtype = par->u.tag.element->tag->kind;
777 for (; tlist; tlist = tlist->next)
779 /* consider source */
781 assert(tlist->source);
782 sp_parse(n, wrd, tlist->source);
786 if (p->flagShowRecords)
789 printf("%*sIdx: [%s]", (level + 1) * 4, "",
791 printf("%s:%s [%d] %s",
792 tlist->att->parent->name,
793 tlist->att->name, tlist->att->value,
795 printf (" XData:\"");
796 for (i = 0; i<wrd->length && i < 40; i++)
797 fputc (wrd->string[i], stdout);
799 if (wrd->length > 40)
801 fputc ('\n', stdout);
805 wrd->reg_type = *tlist->structure;
806 wrd->attrSet = (int) (tlist->att->parent->reference);
807 wrd->attrUse = tlist->att->locals->local;
814 static int dumpkeys(data1_node *n, struct recExtractCtrl *p, int level,
817 for (; n; n = n->next)
819 if (p->flagShowRecords) /* display element description to user */
821 if (n->which == DATA1N_root)
823 printf("%*s", level * 4, "");
824 printf("Record type: '%s'\n", n->u.root.type);
826 else if (n->which == DATA1N_tag)
830 printf("%*s", level * 4, "");
831 if (!(e = n->u.tag.element))
832 printf("Local tag: '%s'\n", n->u.tag.tag);
835 printf("Elm: '%s' ", e->name);
838 data1_tag *t = e->tag;
840 printf("TagNam: '%s' ", t->names->name);
843 printf("%s[%d],", t->tagset->name, t->tagset->type);
846 if (t->which == DATA1T_numeric)
847 printf("%d)", t->value.numeric);
849 printf("'%s')", t->value.string);
856 if (n->which == DATA1N_tag)
858 index_termlist (n, n, p, level, wrd);
859 /* index start tag */
860 if (n->root->u.root.absyn)
861 index_xpath (n, p, level, wrd, 1);
865 if (dumpkeys(n->child, p, level + 1, wrd) < 0)
869 if (n->which == DATA1N_data)
871 data1_node *par = get_parent_tag(p->dh, n);
873 if (p->flagShowRecords)
875 printf("%*s", level * 4, "");
877 if (n->u.data.len > 256)
878 printf("'%.170s ... %.70s'\n", n->u.data.data,
879 n->u.data.data + n->u.data.len-70);
880 else if (n->u.data.len > 0)
881 printf("'%.*s'\n", n->u.data.len, n->u.data.data);
887 index_termlist (par, n, p, level, wrd);
889 index_xpath (n, p, level, wrd, 1016);
892 if (n->which == DATA1N_tag)
895 index_xpath (n, p, level, wrd, 2);
898 if (p->flagShowRecords && n->which == DATA1N_root)
900 printf("%*s-------------\n\n", level * 4, "");
906 int grs_extract_tree(struct recExtractCtrl *p, data1_node *n)
909 int oidtmp[OID_SIZE];
912 oe.proto = PROTO_Z3950;
913 oe.oclass = CLASS_SCHEMA;
916 oe.value = n->u.root.absyn->reference;
918 if ((oid_ent_to_oid (&oe, oidtmp)))
919 (*p->schemaAdd)(p, oidtmp);
923 return dumpkeys(n, p, 0, &wrd);
926 static int grs_extract_sub(struct grs_handlers *h, struct recExtractCtrl *p,
930 struct grs_read_info gri;
932 int oidtmp[OID_SIZE];
935 gri.readf = p->readf;
936 gri.seekf = p->seekf;
937 gri.tellf = p->tellf;
940 gri.offset = p->offset;
944 if (read_grs_type (h, &gri, p->subType, &n))
945 return RECCTRL_EXTRACT_ERROR_NO_SUCH_FILTER;
947 return RECCTRL_EXTRACT_EOF;
948 oe.proto = PROTO_Z3950;
949 oe.oclass = CLASS_SCHEMA;
951 if (!n->u.root.absyn)
952 return RECCTRL_EXTRACT_ERROR;
956 oe.value = n->u.root.absyn->reference;
957 if ((oid_ent_to_oid (&oe, oidtmp)))
958 (*p->schemaAdd)(p, oidtmp);
960 data1_concat_text(p->dh, mem, n);
962 /* ensure our data1 tree is UTF-8 */
963 data1_iconv (p->dh, mem, n, "UTF-8", data1_get_encoding(p->dh, n));
966 data1_pr_tree (p->dh, n, stdout);
970 if (dumpkeys(n, p, 0, &wrd) < 0)
972 data1_free_tree(p->dh, n);
973 return RECCTRL_EXTRACT_ERROR_GENERIC;
975 data1_free_tree(p->dh, n);
976 return RECCTRL_EXTRACT_OK;
979 static int grs_extract(void *clientData, struct recExtractCtrl *p)
982 NMEM mem = nmem_create ();
983 struct grs_handlers *h = (struct grs_handlers *) clientData;
985 ret = grs_extract_sub(h, p, mem);
991 * Return: -1: Nothing done. 0: Ok. >0: Bib-1 diagnostic.
993 static int process_comp(data1_handle dh, data1_node *n, Z_RecordComposition *c)
995 data1_esetname *eset;
1001 case Z_RecordComp_simple:
1002 if (c->u.simple->which != Z_ElementSetNames_generic)
1003 return 26; /* only generic form supported. Fix this later */
1004 if (!(eset = data1_getesetbyname(dh, n->u.root.absyn,
1005 c->u.simple->u.generic)))
1007 yaz_log(LOG_LOG, "Unknown esetname '%s'", c->u.simple->u.generic);
1008 return 25; /* invalid esetname */
1010 yaz_log(LOG_DEBUG, "Esetname '%s' in simple compspec",
1011 c->u.simple->u.generic);
1014 case Z_RecordComp_complex:
1015 if (c->u.complex->generic)
1017 /* insert check for schema */
1018 if ((p = c->u.complex->generic->elementSpec))
1022 case Z_ElementSpec_elementSetName:
1024 data1_getesetbyname(dh, n->u.root.absyn,
1025 p->u.elementSetName)))
1027 yaz_log(LOG_LOG, "Unknown esetname '%s'",
1028 p->u.elementSetName);
1029 return 25; /* invalid esetname */
1031 yaz_log(LOG_DEBUG, "Esetname '%s' in complex compspec",
1032 p->u.elementSetName);
1035 case Z_ElementSpec_externalSpec:
1036 if (p->u.externalSpec->which == Z_External_espec1)
1038 yaz_log(LOG_DEBUG, "Got Espec-1");
1039 espec = p->u.externalSpec-> u.espec1;
1043 yaz_log(LOG_LOG, "Unknown external espec.");
1044 return 25; /* bad. what is proper diagnostic? */
1051 return 26; /* fix */
1055 yaz_log(LOG_DEBUG, "Element: Espec-1 match");
1056 return data1_doespec1(dh, n, espec);
1060 yaz_log(LOG_DEBUG, "Element: all match");
1065 /* Add Zebra info in separate namespace ...
1068 <metadata xmlns="http://www.indexdata.dk/zebra/">
1070 <localnumber>447</localnumber>
1071 <filename>records/genera.xml</filename>
1076 static void zebra_xml_metadata (struct recRetrieveCtrl *p, data1_node *top,
1079 const char *idzebra_ns[3];
1080 const char *i2 = "\n ";
1081 const char *i4 = "\n ";
1084 idzebra_ns[0] = "xmlns";
1085 idzebra_ns[1] = "http://www.indexdata.dk/zebra/";
1088 data1_mk_text (p->dh, mem, i2, top);
1090 n = data1_mk_tag (p->dh, mem, "idzebra", idzebra_ns, top);
1092 data1_mk_text (p->dh, mem, "\n", top);
1094 data1_mk_text (p->dh, mem, i4, n);
1096 data1_mk_tag_data_int (p->dh, n, "size", p->recordSize, mem);
1100 data1_mk_text (p->dh, mem, i4, n);
1101 data1_mk_tag_data_int (p->dh, n, "score", p->score, mem);
1103 data1_mk_text (p->dh, mem, i4, n);
1104 data1_mk_tag_data_zint (p->dh, n, "localnumber", p->localno, mem);
1107 data1_mk_text (p->dh, mem, i4, n);
1108 data1_mk_tag_data_text(p->dh, n, "filename", p->fname, mem);
1110 data1_mk_text (p->dh, mem, i2, n);
1113 static int grs_retrieve(void *clientData, struct recRetrieveCtrl *p)
1115 data1_node *node = 0, *onode = 0, *top;
1118 int res, selected = 0;
1120 struct grs_read_info gri;
1121 const char *tagname;
1122 struct grs_handlers *h = (struct grs_handlers *) clientData;
1123 int requested_schema = VAL_NONE;
1124 data1_marctab *marctab;
1127 mem = nmem_create();
1128 gri.readf = p->readf;
1129 gri.seekf = p->seekf;
1130 gri.tellf = p->tellf;
1137 yaz_log(LOG_DEBUG, "grs_retrieve");
1138 if (read_grs_type (h, &gri, p->subType, &node))
1150 data1_concat_text(p->dh, mem, node);
1152 /* ensure our data1 tree is UTF-8 */
1153 data1_iconv (p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1156 data1_pr_tree (p->dh, node, stdout);
1158 top = data1_get_root_tag (p->dh, node);
1160 yaz_log(LOG_DEBUG, "grs_retrieve: size");
1161 tagname = data1_systag_lookup(node->u.root.absyn, "size", "size");
1163 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1165 dnew->u.data.what = DATA1I_text;
1166 dnew->u.data.data = dnew->lbuf;
1167 sprintf(dnew->u.data.data, "%d", p->recordSize);
1168 dnew->u.data.len = strlen(dnew->u.data.data);
1171 tagname = data1_systag_lookup(node->u.root.absyn, "rank", "rank");
1172 if (tagname && p->score >= 0 &&
1173 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1175 yaz_log(LOG_DEBUG, "grs_retrieve: %s", tagname);
1176 dnew->u.data.what = DATA1I_num;
1177 dnew->u.data.data = dnew->lbuf;
1178 sprintf(dnew->u.data.data, "%d", p->score);
1179 dnew->u.data.len = strlen(dnew->u.data.data);
1182 tagname = data1_systag_lookup(node->u.root.absyn, "sysno",
1183 "localControlNumber");
1184 if (tagname && p->localno > 0 &&
1185 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1187 yaz_log(LOG_DEBUG, "grs_retrieve: %s", tagname);
1188 dnew->u.data.what = DATA1I_text;
1189 dnew->u.data.data = dnew->lbuf;
1191 sprintf(dnew->u.data.data, ZINT_FORMAT, p->localno);
1192 dnew->u.data.len = strlen(dnew->u.data.data);
1195 data1_pr_tree (p->dh, node, stdout);
1197 #if YAZ_VERSIONL >= 0x010903L
1198 if (p->comp && p->comp->which == Z_RecordComp_complex &&
1199 p->comp->u.complex->generic &&
1200 p->comp->u.complex->generic->which == Z_Schema_oid &&
1201 p->comp->u.complex->generic->schema.oid)
1203 oident *oe = oid_getentbyoid (p->comp->u.complex->generic->schema.oid);
1205 requested_schema = oe->value;
1208 if (p->comp && p->comp->which == Z_RecordComp_complex &&
1209 p->comp->u.complex->generic && p->comp->u.complex->generic->schema)
1211 oident *oe = oid_getentbyoid (p->comp->u.complex->generic->schema);
1213 requested_schema = oe->value;
1217 /* If schema has been specified, map if possible, then check that
1218 * we got the right one
1220 if (requested_schema != VAL_NONE)
1222 yaz_log(LOG_DEBUG, "grs_retrieve: schema mapping");
1223 for (map = node->u.root.absyn->maptabs; map; map = map->next)
1225 if (map->target_absyn_ref == requested_schema)
1228 if (!(node = data1_map_record(p->dh, onode, map, mem)))
1237 if (node->u.root.absyn &&
1238 requested_schema != node->u.root.absyn->reference)
1240 p->diagnostic = 238;
1246 * Does the requested format match a known syntax-mapping? (this reflects
1247 * the overlap of schema and formatting which is inherent in the MARC
1250 yaz_log(LOG_DEBUG, "grs_retrieve: syntax mapping");
1251 if (node->u.root.absyn)
1252 for (map = node->u.root.absyn->maptabs; map; map = map->next)
1254 if (map->target_absyn_ref == p->input_format)
1257 if (!(node = data1_map_record(p->dh, onode, map, mem)))
1266 yaz_log(LOG_DEBUG, "grs_retrieve: schemaIdentifier");
1267 if (node->u.root.absyn &&
1268 node->u.root.absyn->reference != VAL_NONE &&
1269 p->input_format == VAL_GRS1)
1273 int oidtmp[OID_SIZE];
1275 oe.proto = PROTO_Z3950;
1276 oe.oclass = CLASS_SCHEMA;
1277 oe.value = node->u.root.absyn->reference;
1279 if ((oid = oid_ent_to_oid (&oe, oidtmp)))
1282 data1_handle dh = p->dh;
1286 for (ii = oid; *ii >= 0; ii++)
1290 sprintf(p, "%d", *ii);
1293 if ((dnew = data1_mk_tag_data_wd(dh, top,
1294 "schemaIdentifier", mem)))
1296 dnew->u.data.what = DATA1I_oid;
1297 dnew->u.data.data = (char *) nmem_malloc(mem, p - tmp);
1298 memcpy(dnew->u.data.data, tmp, p - tmp);
1299 dnew->u.data.len = p - tmp;
1304 yaz_log(LOG_DEBUG, "grs_retrieve: element spec");
1305 if (p->comp && (res = process_comp(p->dh, node, p->comp)) > 0)
1307 p->diagnostic = res;
1309 data1_free_tree(p->dh, onode);
1310 data1_free_tree(p->dh, node);
1314 else if (p->comp && !res)
1318 data1_pr_tree (p->dh, node, stdout);
1320 yaz_log(LOG_DEBUG, "grs_retrieve: transfer syntax mapping");
1321 switch (p->output_format = (p->input_format != VAL_NONE ?
1322 p->input_format : VAL_SUTRS))
1325 zebra_xml_metadata (p, top, mem);
1328 data1_pr_tree (p->dh, node, stdout);
1332 data1_iconv (p->dh, mem, node, p->encoding, "UTF-8");
1334 if (!(p->rec_buf = data1_nodetoidsgml(p->dh, node, selected,
1336 p->diagnostic = 238;
1339 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1340 memcpy (new_buf, p->rec_buf, p->rec_len);
1341 p->rec_buf = new_buf;
1346 if (!(p->rec_buf = data1_nodetogr(p->dh, node, selected,
1348 p->diagnostic = 238; /* not available in requested syntax */
1350 p->rec_len = (size_t) (-1);
1353 if (!(p->rec_buf = data1_nodetoexplain(p->dh, node, selected,
1355 p->diagnostic = 238;
1357 p->rec_len = (size_t) (-1);
1360 if (!(p->rec_buf = data1_nodetosummary(p->dh, node, selected,
1362 p->diagnostic = 238;
1364 p->rec_len = (size_t) (-1);
1368 data1_iconv (p->dh, mem, node, p->encoding, "UTF-8");
1369 if (!(p->rec_buf = data1_nodetobuf(p->dh, node, selected,
1371 p->diagnostic = 238;
1374 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1375 memcpy (new_buf, p->rec_buf, p->rec_len);
1376 p->rec_buf = new_buf;
1380 if (!(p->rec_buf = data1_nodetosoif(p->dh, node, selected,
1382 p->diagnostic = 238;
1385 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1386 memcpy (new_buf, p->rec_buf, p->rec_len);
1387 p->rec_buf = new_buf;
1391 if (!node->u.root.absyn)
1393 p->diagnostic = 238;
1396 for (marctab = node->u.root.absyn->marc; marctab;
1397 marctab = marctab->next)
1398 if (marctab->reference == p->input_format)
1402 p->diagnostic = 238;
1406 data1_iconv (p->dh, mem, node, p->encoding, "UTF-8");
1407 if (!(p->rec_buf = data1_nodetomarc(p->dh, marctab, node,
1408 selected, &p->rec_len)))
1409 p->diagnostic = 238;
1412 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1413 memcpy (new_buf, p->rec_buf, p->rec_len);
1414 p->rec_buf = new_buf;
1418 data1_free_tree(p->dh, node);
1420 data1_free_tree(p->dh, onode);
1425 static struct recType grs_type =
1434 RecType recTypeGrs = &grs_type;