1 /* $Id: recgrs.c,v 1.96 2004-12-21 22:02:28 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>
35 #include <idzebra/recgrs.h>
37 #define GRS_MAX_WORD 512
39 struct source_parser {
46 static int sp_lex(struct source_parser *sp)
48 while (*sp->src == ' ')
52 while (*sp->src && !strchr("<>();,-: ", *sp->src))
61 sp->lookahead = *sp->src;
69 static int sp_expr(struct source_parser *sp, data1_node *n, RecWord *wrd)
71 if (sp->lookahead != 't')
73 if (sp->len == 4 && !memcmp(sp->tok, "data", sp->len))
75 if (n->which == DATA1N_data)
77 wrd->string = n->u.data.data;
78 wrd->length = n->u.data.len;
82 else if (sp->len == 3 && !memcmp(sp->tok, "tag", sp->len))
84 if (n->which == DATA1N_tag)
86 wrd->string = n->u.tag.tag;
87 wrd->length = strlen(n->u.tag.tag);
91 else if (sp->len == 4 && !memcmp(sp->tok, "attr", sp->len))
94 if (sp->lookahead != '(')
97 if (sp->lookahead != 't')
100 if (n->which == DATA1N_tag)
102 data1_xattr *p = n->u.tag.attributes;
103 while (p && strlen(p->name) != sp->len &&
104 memcmp (p->name, sp->tok, sp->len))
108 wrd->string = p->value;
109 wrd->length = strlen(p->value);
113 if (sp->lookahead != ')')
117 else if (sp->len == 5 && !memcmp(sp->tok, "range", sp->len))
121 if (sp->lookahead != '(')
126 if (sp->lookahead != ',')
130 if (sp->lookahead != 't')
132 start = atoi_n(sp->tok, sp->len);
135 if (sp->lookahead != ',')
139 if (sp->lookahead != 't')
141 len = atoi_n(sp->tok, sp->len);
144 if (sp->lookahead != ')')
148 if (wrd->string && wrd->length)
150 wrd->string += start;
151 wrd->length -= start;
152 if (wrd->length > len)
159 static int sp_parse(data1_node *n, RecWord *wrd, const char *src)
161 struct source_parser sp;
168 return sp_expr(&sp, n, wrd);
171 int d1_check_xpath_predicate(data1_node *n, struct xpath_predicate *p)
180 if (p->which == XPATH_PREDICATE_RELATION) {
181 if (p->u.relation.name[0]) {
182 if (*p->u.relation.name != '@') {
184 " Only attributes (@) are supported in xelm xpath predicates");
185 yaz_log(YLOG_WARN, "predicate %s ignored", p->u.relation.name);
188 attname = p->u.relation.name + 1;
190 /* looking for the attribute with a specified name */
191 for (attr = n->u.tag.attributes; attr; attr = attr->next) {
192 yaz_log(YLOG_DEBUG," - attribute %s <-> %s", attname, attr->name );
194 if (!strcmp(attr->name, attname)) {
195 if (p->u.relation.op[0]) {
196 if (*p->u.relation.op != '=') {
198 "Only '=' relation is supported (%s)",p->u.relation.op);
199 yaz_log(YLOG_WARN, "predicate %s ignored", p->u.relation.name);
202 yaz_log(YLOG_DEBUG," - value %s <-> %s",
203 p->u.relation.value, attr->value );
204 if (!strcmp(attr->value, p->u.relation.value)) {
209 /* attribute exists, no value specified */
214 yaz_log(YLOG_DEBUG, "return %d", res);
220 else if (p->which == XPATH_PREDICATE_BOOLEAN) {
221 if (!strcmp(p->u.boolean.op,"and")) {
222 return d1_check_xpath_predicate(n, p->u.boolean.left)
223 && d1_check_xpath_predicate(n, p->u.boolean.right);
225 else if (!strcmp(p->u.boolean.op,"or")) {
226 return (d1_check_xpath_predicate(n, p->u.boolean.left)
227 || d1_check_xpath_predicate(n, p->u.boolean.right));
229 yaz_log(YLOG_WARN, "Unknown boolean relation %s, ignored",p->u.boolean.op);
240 New function, looking for xpath "element" definitions in abs, by
241 tagpath, using a kind of ugly regxp search.The DFA was built while
242 parsing abs, so here we just go trough them and try to match
243 against the given tagpath. The first matching entry is returned.
247 Added support for enhanced xelm. Now [] predicates are considered
248 as well, when selecting indexing rules... (why the hell it's called
255 data1_termlist *xpath_termlist_by_tagpath(char *tagpath, data1_node *n)
257 data1_absyn *abs = n->root->u.root.absyn;
258 data1_xpelement *xpe = abs->xp_elements;
261 struct xpath_location_step *xp;
264 char *pexpr = xmalloc(strlen(tagpath)+2);
267 sprintf (pexpr, "%s\n", tagpath);
268 yaz_log(YLOG_DEBUG,"Checking tagpath %s",tagpath);
271 struct DFA_state **dfaar = xpe->dfa->states;
272 struct DFA_state *s=dfaar[0];
279 c = *pexpr++; t = s->trans; i = s->tran_no;
280 if ((c >= t->ch[0] && c <= t->ch[1]) || (!t->ch[0])) {
283 if ((s = dfaar[t->to])->rule_no &&
284 (start_line || s->rule_nno)) {
288 for (t=s->trans, i=s->tran_no; --i >= 0; t++) {
289 if ((unsigned) *p >= t->ch[0] && (unsigned) *p <= t->ch[1])
296 yaz_log(YLOG_DEBUG," xpath match %s",xpe->xpath_expr);
298 yaz_log(YLOG_DEBUG," xpath no match %s",xpe->xpath_expr);
303 /* we have to check the perdicates up to the root node */
306 /* find the first tag up in the node structure */
307 nn = n; while (nn && nn->which != DATA1N_tag) {
311 /* go from inside out in the node structure, while going
312 backwards trough xpath location steps ... */
313 for (i=xpe->xpath_len - 1; i>0; i--) {
315 yaz_log(YLOG_DEBUG,"Checking step %d: %s on tag %s",
316 i,xp[i].part,nn->u.tag.tag);
318 if (!d1_check_xpath_predicate(nn, xp[i].predicate)) {
319 yaz_log(YLOG_DEBUG," Predicates didn't match");
324 if (nn->which == DATA1N_tag) {
339 yaz_log(YLOG_DEBUG,"Got it");
340 return xpe->termlists;
347 1 start element (tag)
349 3 start attr (and attr-exact)
357 Now, if there is a matching xelm described in abs, for the
358 indexed element or the attribute, then the data is handled according
359 to those definitions...
361 modified by pop, 2002-12-13
364 /* add xpath index for an attribute */
365 static void index_xpath_attr (char *tag_path, char *name, char *value,
366 char *structure, struct recExtractCtrl *p,
369 wrd->attrSet = VAL_IDXPATH;
372 wrd->string = tag_path;
373 wrd->length = strlen(tag_path);
380 wrd->length = strlen(value);
386 wrd->string = tag_path;
387 wrd->length = strlen(tag_path);
392 static void index_xpath (data1_node *n, struct recExtractCtrl *p,
393 int level, RecWord *wrd, int use)
396 char tag_path_full[1024];
399 int termlist_only = 1;
403 yaz_log(YLOG_DEBUG, "index_xpath level=%d use=%d", level, use);
404 if ((!n->root->u.root.absyn) ||
405 (n->root->u.root.absyn->enable_xpath_indexing)) {
412 wrd->string = n->u.data.data;
413 wrd->length = n->u.data.len;
417 /* we have to fetch the whole path to the data tag */
418 for (nn = n; nn; nn = nn->parent) {
419 if (nn->which == DATA1N_tag) {
420 size_t tlen = strlen(nn->u.tag.tag);
421 if (tlen + flen > (sizeof(tag_path_full)-2)) return;
422 memcpy (tag_path_full + flen, nn->u.tag.tag, tlen);
424 tag_path_full[flen++] = '/';
426 else if (nn->which == DATA1N_root) break;
429 tag_path_full[flen] = 0;
431 /* If we have a matching termlist... */
432 if (n->root->u.root.absyn &&
433 (tl = xpath_termlist_by_tagpath(tag_path_full, n)))
435 for (; tl; tl = tl->next)
437 /* need to copy recword because it may be changed */
439 wrd->reg_type = *tl->structure;
440 /* this is the ! case, so structure is for the xpath index */
441 memcpy (&wrd_tl, wrd, sizeof(*wrd));
443 sp_parse(n, &wrd_tl, tl->source);
445 wrd_tl.attrSet = VAL_IDXPATH;
446 wrd_tl.attrUse = use;
447 if (p->flagShowRecords)
450 printf("%*sXPath index", (level + 1) * 4, "");
451 printf (" XData:\"");
452 for (i = 0; i<wrd_tl.length && i < 40; i++)
453 fputc (wrd_tl.string[i], stdout);
455 if (wrd_tl.length > 40)
457 fputc ('\n', stdout);
460 (*p->tokenAdd)(&wrd_tl);
463 /* this is just the old fashioned attribute based index */
464 wrd_tl.attrSet = (int) (tl->att->parent->reference);
465 wrd_tl.attrUse = tl->att->locals->local;
466 if (p->flagShowRecords)
469 printf("%*sIdx: [%s]", (level + 1) * 4, "",
471 printf("%s:%s [%d] %s",
472 tl->att->parent->name,
473 tl->att->name, tl->att->value,
475 printf (" XData:\"");
476 for (i = 0; i<wrd_tl.length && i < 40; i++)
477 fputc (wrd_tl.string[i], stdout);
479 if (wrd_tl.length > 40)
481 fputc ('\n', stdout);
484 (*p->tokenAdd)(&wrd_tl);
488 /* xpath indexing is done, if there was no termlist given,
489 or no ! in the termlist, and default indexing is enabled... */
490 if (!p->flagShowRecords && !xpdone && !termlist_only)
492 wrd->attrSet = VAL_IDXPATH;
500 for (nn = n; nn; nn = nn->parent)
502 if (nn->which == DATA1N_tag)
504 size_t tlen = strlen(nn->u.tag.tag);
505 if (tlen + flen > (sizeof(tag_path_full)-2))
507 memcpy (tag_path_full + flen, nn->u.tag.tag, tlen);
509 tag_path_full[flen++] = '/';
511 else if (nn->which == DATA1N_root)
517 wrd->string = tag_path_full;
519 wrd->attrSet = VAL_IDXPATH;
521 if (p->flagShowRecords)
523 printf("%*s tag=", (level + 1) * 4, "");
524 for (i = 0; i<wrd->length && i < 40; i++)
525 fputc (wrd->string[i], stdout);
536 tag_path_full[flen] = 0;
538 /* Add tag start/end xpath index, only when there is a ! in the apropriate xelm
539 directive, or default xpath indexing is enabled */
540 if (!(do_xpindex = 1 - termlist_only)) {
541 if ((tl = xpath_termlist_by_tagpath(tag_path_full, n))) {
542 for (; tl; tl = tl->next) { if (!tl->att) {do_xpindex = 1;} }
546 (*p->tokenAdd)(wrd); /* index element pag (AKA tag path) */
549 if (use == 1) /* only for the starting tag... */
551 #define MAX_ATTR_COUNT 50
552 data1_termlist *tll[MAX_ATTR_COUNT];
556 /* get termlists for attributes, and find out, if we have to do xpath indexing */
557 for (xp = n->u.tag.attributes; xp; xp = xp->next) {
562 for (xp = n->u.tag.attributes; xp; xp = xp->next) {
564 int do_xpindex = 1 - termlist_only;
566 char attr_tag_path_full[1024];
569 /* this could be cached as well */
570 sprintf (attr_tag_path_full, "@%s/%.*s",
571 xp->name, int_len, tag_path_full);
573 tll[i] = xpath_termlist_by_tagpath(attr_tag_path_full,n);
575 /* if there is a ! in the xelm termlist, or default indexing is on,
576 proceed with xpath idx */
579 for (; tl; tl = tl->next)
588 /* attribute (no value) */
591 wrd->string = xp->name;
592 wrd->length = strlen(xp->name);
598 strlen(xp->name) + strlen(xp->value) < sizeof(comb)-2) {
600 /* attribute value exact */
601 strcpy (comb, xp->name);
603 strcat (comb, xp->value);
608 wrd->length = strlen(comb);
618 for (xp = n->u.tag.attributes; xp; xp = xp->next) {
620 char attr_tag_path_full[1024];
624 sprintf (attr_tag_path_full, "@%s/%.*s",
625 xp->name, int_len, tag_path_full);
629 /* If there is a termlist given (=xelm directive) */
630 for (; tl; tl = tl->next)
633 /* add xpath index for the attribute */
634 index_xpath_attr (attr_tag_path_full, xp->name,
635 xp->value, tl->structure,
639 /* add attribute based index for the attribute */
642 (tl->att->parent->reference);
643 wrd->attrUse = tl->att->locals->local;
644 wrd->reg_type = *tl->structure;
645 wrd->string = xp->value;
646 wrd->length = strlen(xp->value);
652 /* if there was no termlist for the given path,
653 or the termlist didn't have a ! element, index
654 the attribute as "w" */
655 if ((!xpdone) && (!termlist_only))
657 index_xpath_attr (attr_tag_path_full, xp->name,
658 xp->value, "w", p, wrd);
667 static void index_termlist (data1_node *par, data1_node *n,
668 struct recExtractCtrl *p, int level, RecWord *wrd)
670 data1_termlist *tlist = 0;
671 data1_datatype dtype = DATA1K_string;
674 * cycle up towards the root until we find a tag with an att..
675 * this has the effect of indexing locally defined tags with
676 * the attribute of their ancestor in the record.
679 while (!par->u.tag.element)
680 if (!par->parent || !(par=get_parent_tag(p->dh, par->parent)))
682 if (!par || !(tlist = par->u.tag.element->termlists))
684 if (par->u.tag.element->tag)
685 dtype = par->u.tag.element->tag->kind;
687 for (; tlist; tlist = tlist->next)
689 /* consider source */
691 assert(tlist->source);
692 sp_parse(n, wrd, tlist->source);
696 if (p->flagShowRecords)
699 printf("%*sIdx: [%s]", (level + 1) * 4, "",
701 printf("%s:%s [%d] %s",
702 tlist->att->parent->name,
703 tlist->att->name, tlist->att->value,
705 printf (" XData:\"");
706 for (i = 0; i<wrd->length && i < 40; i++)
707 fputc (wrd->string[i], stdout);
709 if (wrd->length > 40)
711 fputc ('\n', stdout);
715 wrd->reg_type = *tlist->structure;
716 wrd->attrSet = (int) (tlist->att->parent->reference);
717 wrd->attrUse = tlist->att->locals->local;
724 static int dumpkeys(data1_node *n, struct recExtractCtrl *p, int level,
727 for (; n; n = n->next)
729 if (p->flagShowRecords) /* display element description to user */
731 if (n->which == DATA1N_root)
733 printf("%*s", level * 4, "");
734 printf("Record type: '%s'\n", n->u.root.type);
736 else if (n->which == DATA1N_tag)
740 printf("%*s", level * 4, "");
741 if (!(e = n->u.tag.element))
742 printf("Local tag: '%s'\n", n->u.tag.tag);
745 printf("Elm: '%s' ", e->name);
748 data1_tag *t = e->tag;
750 printf("TagNam: '%s' ", t->names->name);
753 printf("%s[%d],", t->tagset->name, t->tagset->type);
756 if (t->which == DATA1T_numeric)
757 printf("%d)", t->value.numeric);
759 printf("'%s')", t->value.string);
766 if (n->which == DATA1N_tag)
768 index_termlist (n, n, p, level, wrd);
769 /* index start tag */
770 if (n->root->u.root.absyn)
771 index_xpath (n, p, level, wrd, 1);
775 if (dumpkeys(n->child, p, level + 1, wrd) < 0)
779 if (n->which == DATA1N_data)
781 data1_node *par = get_parent_tag(p->dh, n);
783 if (p->flagShowRecords)
785 printf("%*s", level * 4, "");
787 if (n->u.data.len > 256)
788 printf("'%.170s ... %.70s'\n", n->u.data.data,
789 n->u.data.data + n->u.data.len-70);
790 else if (n->u.data.len > 0)
791 printf("'%.*s'\n", n->u.data.len, n->u.data.data);
797 index_termlist (par, n, p, level, wrd);
799 index_xpath (n, p, level, wrd, 1016);
802 if (n->which == DATA1N_tag)
805 index_xpath (n, p, level, wrd, 2);
808 if (p->flagShowRecords && n->which == DATA1N_root)
810 printf("%*s-------------\n\n", level * 4, "");
816 int grs_extract_tree(struct recExtractCtrl *p, data1_node *n)
819 int oidtmp[OID_SIZE];
822 oe.proto = PROTO_Z3950;
823 oe.oclass = CLASS_SCHEMA;
826 oe.value = n->u.root.absyn->reference;
828 if ((oid_ent_to_oid (&oe, oidtmp)))
829 (*p->schemaAdd)(p, oidtmp);
833 return dumpkeys(n, p, 0, &wrd);
836 static int grs_extract_sub(void *clientData, struct recExtractCtrl *p,
838 data1_node *(*grs_read)(struct grs_read_info *))
841 struct grs_read_info gri;
843 int oidtmp[OID_SIZE];
846 gri.readf = p->readf;
847 gri.seekf = p->seekf;
848 gri.tellf = p->tellf;
851 gri.offset = p->offset;
854 gri.clientData = clientData;
856 n = (*grs_read)(&gri);
858 return RECCTRL_EXTRACT_EOF;
859 oe.proto = PROTO_Z3950;
860 oe.oclass = CLASS_SCHEMA;
862 if (!n->u.root.absyn)
863 return RECCTRL_EXTRACT_ERROR;
867 oe.value = n->u.root.absyn->reference;
868 if ((oid_ent_to_oid (&oe, oidtmp)))
869 (*p->schemaAdd)(p, oidtmp);
871 data1_concat_text(p->dh, mem, n);
873 /* ensure our data1 tree is UTF-8 */
874 data1_iconv (p->dh, mem, n, "UTF-8", data1_get_encoding(p->dh, n));
877 data1_pr_tree (p->dh, n, stdout);
881 if (dumpkeys(n, p, 0, &wrd) < 0)
883 data1_free_tree(p->dh, n);
884 return RECCTRL_EXTRACT_ERROR_GENERIC;
886 data1_free_tree(p->dh, n);
887 return RECCTRL_EXTRACT_OK;
890 int zebra_grs_extract(void *clientData, struct recExtractCtrl *p,
891 data1_node *(*grs_read)(struct grs_read_info *))
894 NMEM mem = nmem_create ();
895 ret = grs_extract_sub(clientData, p, mem, grs_read);
901 * Return: -1: Nothing done. 0: Ok. >0: Bib-1 diagnostic.
903 static int process_comp(data1_handle dh, data1_node *n, Z_RecordComposition *c,
904 char **addinfo, ODR o)
906 data1_esetname *eset;
912 case Z_RecordComp_simple:
913 if (c->u.simple->which != Z_ElementSetNames_generic)
914 return 26; /* only generic form supported. Fix this later */
915 if (!(eset = data1_getesetbyname(dh, n->u.root.absyn,
916 c->u.simple->u.generic)))
918 yaz_log(YLOG_LOG, "Unknown esetname '%s'", c->u.simple->u.generic);
919 *addinfo = odr_strdup(o, c->u.simple->u.generic);
920 return 25; /* invalid esetname */
922 yaz_log(YLOG_DEBUG, "Esetname '%s' in simple compspec",
923 c->u.simple->u.generic);
926 case Z_RecordComp_complex:
927 if (c->u.complex->generic)
929 /* insert check for schema */
930 if ((p = c->u.complex->generic->elementSpec))
934 case Z_ElementSpec_elementSetName:
936 data1_getesetbyname(dh, n->u.root.absyn,
937 p->u.elementSetName)))
939 yaz_log(YLOG_DEBUG, "Unknown esetname '%s'",
940 p->u.elementSetName);
941 *addinfo = odr_strdup(o, p->u.elementSetName);
942 return 25; /* invalid esetname */
944 yaz_log(YLOG_DEBUG, "Esetname '%s' in complex compspec",
945 p->u.elementSetName);
948 case Z_ElementSpec_externalSpec:
949 if (p->u.externalSpec->which == Z_External_espec1)
951 yaz_log(YLOG_DEBUG, "Got Espec-1");
952 espec = p->u.externalSpec-> u.espec1;
956 yaz_log(YLOG_LOG, "Unknown external espec.");
957 return 25; /* bad. what is proper diagnostic? */
968 yaz_log(YLOG_DEBUG, "Element: Espec-1 match");
969 return data1_doespec1(dh, n, espec);
973 yaz_log(YLOG_DEBUG, "Element: all match");
978 /* Add Zebra info in separate namespace ...
981 <metadata xmlns="http://www.indexdata.dk/zebra/">
983 <localnumber>447</localnumber>
984 <filename>records/genera.xml</filename>
989 static void zebra_xml_metadata (struct recRetrieveCtrl *p, data1_node *top,
992 const char *idzebra_ns[3];
993 const char *i2 = "\n ";
994 const char *i4 = "\n ";
997 idzebra_ns[0] = "xmlns";
998 idzebra_ns[1] = "http://www.indexdata.dk/zebra/";
1001 data1_mk_text (p->dh, mem, i2, top);
1003 n = data1_mk_tag (p->dh, mem, "idzebra", idzebra_ns, top);
1005 data1_mk_text (p->dh, mem, "\n", top);
1007 data1_mk_text (p->dh, mem, i4, n);
1009 data1_mk_tag_data_int (p->dh, n, "size", p->recordSize, mem);
1013 data1_mk_text (p->dh, mem, i4, n);
1014 data1_mk_tag_data_int (p->dh, n, "score", p->score, mem);
1016 data1_mk_text (p->dh, mem, i4, n);
1017 data1_mk_tag_data_zint (p->dh, n, "localnumber", p->localno, mem);
1020 data1_mk_text (p->dh, mem, i4, n);
1021 data1_mk_tag_data_text(p->dh, n, "filename", p->fname, mem);
1023 data1_mk_text (p->dh, mem, i2, n);
1026 int zebra_grs_retrieve(void *clientData, struct recRetrieveCtrl *p,
1027 data1_node *(*grs_read)(struct grs_read_info *))
1029 data1_node *node = 0, *onode = 0, *top;
1032 int res, selected = 0;
1034 struct grs_read_info gri;
1035 const char *tagname;
1037 int requested_schema = VAL_NONE;
1038 data1_marctab *marctab;
1041 mem = nmem_create();
1042 gri.readf = p->readf;
1043 gri.seekf = p->seekf;
1044 gri.tellf = p->tellf;
1050 gri.clientData = clientData;
1052 yaz_log(YLOG_DEBUG, "grs_retrieve");
1053 node = (*grs_read)(&gri);
1060 data1_concat_text(p->dh, mem, node);
1063 data1_pr_tree (p->dh, node, stdout);
1065 top = data1_get_root_tag (p->dh, node);
1067 yaz_log(YLOG_DEBUG, "grs_retrieve: size");
1068 tagname = data1_systag_lookup(node->u.root.absyn, "size", "size");
1070 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1072 dnew->u.data.what = DATA1I_text;
1073 dnew->u.data.data = dnew->lbuf;
1074 sprintf(dnew->u.data.data, "%d", p->recordSize);
1075 dnew->u.data.len = strlen(dnew->u.data.data);
1078 tagname = data1_systag_lookup(node->u.root.absyn, "rank", "rank");
1079 if (tagname && p->score >= 0 &&
1080 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1082 yaz_log(YLOG_DEBUG, "grs_retrieve: %s", tagname);
1083 dnew->u.data.what = DATA1I_num;
1084 dnew->u.data.data = dnew->lbuf;
1085 sprintf(dnew->u.data.data, "%d", p->score);
1086 dnew->u.data.len = strlen(dnew->u.data.data);
1089 tagname = data1_systag_lookup(node->u.root.absyn, "sysno",
1090 "localControlNumber");
1091 if (tagname && p->localno > 0 &&
1092 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1094 yaz_log(YLOG_DEBUG, "grs_retrieve: %s", tagname);
1095 dnew->u.data.what = DATA1I_text;
1096 dnew->u.data.data = dnew->lbuf;
1098 sprintf(dnew->u.data.data, ZINT_FORMAT, p->localno);
1099 dnew->u.data.len = strlen(dnew->u.data.data);
1102 if (p->input_format == VAL_TEXT_XML)
1103 zebra_xml_metadata (p, top, mem);
1106 data1_pr_tree (p->dh, node, stdout);
1108 if (p->comp && p->comp->which == Z_RecordComp_complex &&
1109 p->comp->u.complex->generic &&
1110 p->comp->u.complex->generic->which == Z_Schema_oid &&
1111 p->comp->u.complex->generic->schema.oid)
1113 oident *oe = oid_getentbyoid (p->comp->u.complex->generic->schema.oid);
1115 requested_schema = oe->value;
1117 /* If schema has been specified, map if possible, then check that
1118 * we got the right one
1120 if (requested_schema != VAL_NONE)
1122 yaz_log(YLOG_DEBUG, "grs_retrieve: schema mapping");
1123 for (map = node->u.root.absyn->maptabs; map; map = map->next)
1125 if (map->target_absyn_ref == requested_schema)
1128 if (!(node = data1_map_record(p->dh, onode, map, mem)))
1137 if (node->u.root.absyn &&
1138 requested_schema != node->u.root.absyn->reference)
1140 p->diagnostic = 238;
1146 * Does the requested format match a known syntax-mapping? (this reflects
1147 * the overlap of schema and formatting which is inherent in the MARC
1150 yaz_log(YLOG_DEBUG, "grs_retrieve: syntax mapping");
1151 if (node->u.root.absyn)
1152 for (map = node->u.root.absyn->maptabs; map; map = map->next)
1154 if (map->target_absyn_ref == p->input_format)
1157 if (!(node = data1_map_record(p->dh, onode, map, mem)))
1166 yaz_log(YLOG_DEBUG, "grs_retrieve: schemaIdentifier");
1167 if (node->u.root.absyn &&
1168 node->u.root.absyn->reference != VAL_NONE &&
1169 p->input_format == VAL_GRS1)
1173 int oidtmp[OID_SIZE];
1175 oe.proto = PROTO_Z3950;
1176 oe.oclass = CLASS_SCHEMA;
1177 oe.value = node->u.root.absyn->reference;
1179 if ((oid = oid_ent_to_oid (&oe, oidtmp)))
1182 data1_handle dh = p->dh;
1186 for (ii = oid; *ii >= 0; ii++)
1190 sprintf(p, "%d", *ii);
1193 if ((dnew = data1_mk_tag_data_wd(dh, top,
1194 "schemaIdentifier", mem)))
1196 dnew->u.data.what = DATA1I_oid;
1197 dnew->u.data.data = (char *) nmem_malloc(mem, p - tmp);
1198 memcpy(dnew->u.data.data, tmp, p - tmp);
1199 dnew->u.data.len = p - tmp;
1204 yaz_log(YLOG_DEBUG, "grs_retrieve: element spec");
1205 if (p->comp && (res = process_comp(p->dh, node, p->comp, &p->addinfo,
1208 p->diagnostic = res;
1210 data1_free_tree(p->dh, onode);
1211 data1_free_tree(p->dh, node);
1215 else if (p->comp && !res)
1219 data1_pr_tree (p->dh, node, stdout);
1221 yaz_log(YLOG_DEBUG, "grs_retrieve: transfer syntax mapping");
1222 switch (p->output_format = (p->input_format != VAL_NONE ?
1223 p->input_format : VAL_SUTRS))
1227 data1_pr_tree (p->dh, node, stdout);
1229 /* default output encoding for XML is UTF-8 */
1230 data1_iconv (p->dh, mem, node,
1231 p->encoding ? p->encoding : "UTF-8",
1232 data1_get_encoding(p->dh, node));
1234 if (!(p->rec_buf = data1_nodetoidsgml(p->dh, node, selected,
1236 p->diagnostic = 238;
1239 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1240 memcpy (new_buf, p->rec_buf, p->rec_len);
1241 p->rec_buf = new_buf;
1245 data1_iconv (p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1247 if (!(p->rec_buf = data1_nodetogr(p->dh, node, selected,
1249 p->diagnostic = 238; /* not available in requested syntax */
1251 p->rec_len = (size_t) (-1);
1254 /* ensure our data1 tree is UTF-8 */
1255 data1_iconv (p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1257 if (!(p->rec_buf = data1_nodetoexplain(p->dh, node, selected,
1259 p->diagnostic = 238;
1261 p->rec_len = (size_t) (-1);
1264 /* ensure our data1 tree is UTF-8 */
1265 data1_iconv (p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1266 if (!(p->rec_buf = data1_nodetosummary(p->dh, node, selected,
1268 p->diagnostic = 238;
1270 p->rec_len = (size_t) (-1);
1274 data1_iconv (p->dh, mem, node, p->encoding,
1275 data1_get_encoding(p->dh, node));
1276 if (!(p->rec_buf = data1_nodetobuf(p->dh, node, selected,
1278 p->diagnostic = 238;
1281 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1282 memcpy (new_buf, p->rec_buf, p->rec_len);
1283 p->rec_buf = new_buf;
1288 data1_iconv (p->dh, mem, node, p->encoding,
1289 data1_get_encoding(p->dh, node));
1290 if (!(p->rec_buf = data1_nodetosoif(p->dh, node, selected,
1292 p->diagnostic = 238;
1295 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1296 memcpy (new_buf, p->rec_buf, p->rec_len);
1297 p->rec_buf = new_buf;
1301 if (!node->u.root.absyn)
1303 p->diagnostic = 238;
1306 for (marctab = node->u.root.absyn->marc; marctab;
1307 marctab = marctab->next)
1308 if (marctab->reference == p->input_format)
1312 p->diagnostic = 238;
1316 data1_iconv (p->dh, mem, node, p->encoding,
1317 data1_get_encoding(p->dh, node));
1318 if (!(p->rec_buf = data1_nodetomarc(p->dh, marctab, node,
1319 selected, &p->rec_len)))
1320 p->diagnostic = 238;
1323 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1324 memcpy (new_buf, p->rec_buf, p->rec_len);
1325 p->rec_buf = new_buf;
1329 data1_free_tree(p->dh, node);
1331 data1_free_tree(p->dh, onode);