1 /* $Id: recgrs.c,v 1.97 2005-01-05 00:13:20 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>
34 #include <idzebra/recgrs.h>
36 #define GRS_MAX_WORD 512
38 struct source_parser {
45 static int sp_lex(struct source_parser *sp)
47 while (*sp->src == ' ')
51 while (*sp->src && !strchr("<>();,-: ", *sp->src))
60 sp->lookahead = *sp->src;
68 static int sp_expr(struct source_parser *sp, data1_node *n, RecWord *wrd)
70 if (sp->lookahead != 't')
72 if (sp->len == 4 && !memcmp(sp->tok, "data", sp->len))
74 if (n->which == DATA1N_data)
76 wrd->string = n->u.data.data;
77 wrd->length = n->u.data.len;
81 else if (sp->len == 3 && !memcmp(sp->tok, "tag", sp->len))
83 if (n->which == DATA1N_tag)
85 wrd->string = n->u.tag.tag;
86 wrd->length = strlen(n->u.tag.tag);
90 else if (sp->len == 4 && !memcmp(sp->tok, "attr", sp->len))
93 if (sp->lookahead != '(')
96 if (sp->lookahead != 't')
99 if (n->which == DATA1N_tag)
101 data1_xattr *p = n->u.tag.attributes;
102 while (p && strlen(p->name) != sp->len &&
103 memcmp (p->name, sp->tok, sp->len))
107 wrd->string = p->value;
108 wrd->length = strlen(p->value);
112 if (sp->lookahead != ')')
116 else if (sp->len == 5 && !memcmp(sp->tok, "range", sp->len))
120 if (sp->lookahead != '(')
125 if (sp->lookahead != ',')
129 if (sp->lookahead != 't')
131 start = atoi_n(sp->tok, sp->len);
134 if (sp->lookahead != ',')
138 if (sp->lookahead != 't')
140 len = atoi_n(sp->tok, sp->len);
143 if (sp->lookahead != ')')
147 if (wrd->string && wrd->length)
149 wrd->string += start;
150 wrd->length -= start;
151 if (wrd->length > len)
158 static int sp_parse(data1_node *n, RecWord *wrd, const char *src)
160 struct source_parser sp;
167 return sp_expr(&sp, n, wrd);
170 int d1_check_xpath_predicate(data1_node *n, struct xpath_predicate *p)
179 if (p->which == XPATH_PREDICATE_RELATION) {
180 if (p->u.relation.name[0]) {
181 if (*p->u.relation.name != '@') {
183 " Only attributes (@) are supported in xelm xpath predicates");
184 yaz_log(YLOG_WARN, "predicate %s ignored", p->u.relation.name);
187 attname = p->u.relation.name + 1;
189 /* looking for the attribute with a specified name */
190 for (attr = n->u.tag.attributes; attr; attr = attr->next) {
191 yaz_log(YLOG_DEBUG," - attribute %s <-> %s", attname, attr->name );
193 if (!strcmp(attr->name, attname)) {
194 if (p->u.relation.op[0]) {
195 if (*p->u.relation.op != '=') {
197 "Only '=' relation is supported (%s)",p->u.relation.op);
198 yaz_log(YLOG_WARN, "predicate %s ignored", p->u.relation.name);
201 yaz_log(YLOG_DEBUG," - value %s <-> %s",
202 p->u.relation.value, attr->value );
203 if (!strcmp(attr->value, p->u.relation.value)) {
208 /* attribute exists, no value specified */
213 yaz_log(YLOG_DEBUG, "return %d", res);
219 else if (p->which == XPATH_PREDICATE_BOOLEAN) {
220 if (!strcmp(p->u.boolean.op,"and")) {
221 return d1_check_xpath_predicate(n, p->u.boolean.left)
222 && d1_check_xpath_predicate(n, p->u.boolean.right);
224 else if (!strcmp(p->u.boolean.op,"or")) {
225 return (d1_check_xpath_predicate(n, p->u.boolean.left)
226 || d1_check_xpath_predicate(n, p->u.boolean.right));
228 yaz_log(YLOG_WARN, "Unknown boolean relation %s, ignored",p->u.boolean.op);
239 New function, looking for xpath "element" definitions in abs, by
240 tagpath, using a kind of ugly regxp search.The DFA was built while
241 parsing abs, so here we just go trough them and try to match
242 against the given tagpath. The first matching entry is returned.
246 Added support for enhanced xelm. Now [] predicates are considered
247 as well, when selecting indexing rules... (why the hell it's called
254 data1_termlist *xpath_termlist_by_tagpath(char *tagpath, data1_node *n)
256 data1_absyn *abs = n->root->u.root.absyn;
257 data1_xpelement *xpe = abs->xp_elements;
260 struct xpath_location_step *xp;
263 char *pexpr = xmalloc(strlen(tagpath)+2);
266 sprintf (pexpr, "%s\n", tagpath);
267 yaz_log(YLOG_DEBUG,"Checking tagpath %s",tagpath);
270 struct DFA_state **dfaar = xpe->dfa->states;
271 struct DFA_state *s=dfaar[0];
278 c = *pexpr++; t = s->trans; i = s->tran_no;
279 if ((c >= t->ch[0] && c <= t->ch[1]) || (!t->ch[0])) {
282 if ((s = dfaar[t->to])->rule_no &&
283 (start_line || s->rule_nno)) {
287 for (t=s->trans, i=s->tran_no; --i >= 0; t++) {
288 if ((unsigned) *p >= t->ch[0] && (unsigned) *p <= t->ch[1])
295 yaz_log(YLOG_DEBUG," xpath match %s",xpe->xpath_expr);
297 yaz_log(YLOG_DEBUG," xpath no match %s",xpe->xpath_expr);
302 /* we have to check the perdicates up to the root node */
305 /* find the first tag up in the node structure */
306 nn = n; while (nn && nn->which != DATA1N_tag) {
310 /* go from inside out in the node structure, while going
311 backwards trough xpath location steps ... */
312 for (i=xpe->xpath_len - 1; i>0; i--) {
314 yaz_log(YLOG_DEBUG,"Checking step %d: %s on tag %s",
315 i,xp[i].part,nn->u.tag.tag);
317 if (!d1_check_xpath_predicate(nn, xp[i].predicate)) {
318 yaz_log(YLOG_DEBUG," Predicates didn't match");
323 if (nn->which == DATA1N_tag) {
338 yaz_log(YLOG_DEBUG,"Got it");
339 return xpe->termlists;
346 1 start element (tag)
348 3 start attr (and attr-exact)
356 Now, if there is a matching xelm described in abs, for the
357 indexed element or the attribute, then the data is handled according
358 to those definitions...
360 modified by pop, 2002-12-13
363 /* add xpath index for an attribute */
364 static void index_xpath_attr (char *tag_path, char *name, char *value,
365 char *structure, struct recExtractCtrl *p,
368 wrd->attrSet = VAL_IDXPATH;
371 wrd->string = tag_path;
372 wrd->length = strlen(tag_path);
379 wrd->length = strlen(value);
385 wrd->string = tag_path;
386 wrd->length = strlen(tag_path);
391 static void index_xpath (data1_node *n, struct recExtractCtrl *p,
392 int level, RecWord *wrd, int use)
395 char tag_path_full[1024];
398 int termlist_only = 1;
402 yaz_log(YLOG_DEBUG, "index_xpath level=%d use=%d", level, use);
403 if ((!n->root->u.root.absyn) ||
404 (n->root->u.root.absyn->enable_xpath_indexing)) {
411 wrd->string = n->u.data.data;
412 wrd->length = n->u.data.len;
416 /* we have to fetch the whole path to the data tag */
417 for (nn = n; nn; nn = nn->parent) {
418 if (nn->which == DATA1N_tag) {
419 size_t tlen = strlen(nn->u.tag.tag);
420 if (tlen + flen > (sizeof(tag_path_full)-2)) return;
421 memcpy (tag_path_full + flen, nn->u.tag.tag, tlen);
423 tag_path_full[flen++] = '/';
425 else if (nn->which == DATA1N_root) break;
428 tag_path_full[flen] = 0;
430 /* If we have a matching termlist... */
431 if (n->root->u.root.absyn &&
432 (tl = xpath_termlist_by_tagpath(tag_path_full, n)))
434 for (; tl; tl = tl->next)
436 /* need to copy recword because it may be changed */
438 wrd->reg_type = *tl->structure;
439 /* this is the ! case, so structure is for the xpath index */
440 memcpy (&wrd_tl, wrd, sizeof(*wrd));
442 sp_parse(n, &wrd_tl, tl->source);
444 wrd_tl.attrSet = VAL_IDXPATH;
445 wrd_tl.attrUse = use;
446 if (p->flagShowRecords)
449 printf("%*sXPath index", (level + 1) * 4, "");
450 printf (" XData:\"");
451 for (i = 0; i<wrd_tl.length && i < 40; i++)
452 fputc (wrd_tl.string[i], stdout);
454 if (wrd_tl.length > 40)
456 fputc ('\n', stdout);
459 (*p->tokenAdd)(&wrd_tl);
462 /* this is just the old fashioned attribute based index */
463 wrd_tl.attrSet = (int) (tl->att->parent->reference);
464 wrd_tl.attrUse = tl->att->locals->local;
465 if (p->flagShowRecords)
468 printf("%*sIdx: [%s]", (level + 1) * 4, "",
470 printf("%s:%s [%d] %s",
471 tl->att->parent->name,
472 tl->att->name, tl->att->value,
474 printf (" XData:\"");
475 for (i = 0; i<wrd_tl.length && i < 40; i++)
476 fputc (wrd_tl.string[i], stdout);
478 if (wrd_tl.length > 40)
480 fputc ('\n', stdout);
483 (*p->tokenAdd)(&wrd_tl);
487 /* xpath indexing is done, if there was no termlist given,
488 or no ! in the termlist, and default indexing is enabled... */
489 if (!p->flagShowRecords && !xpdone && !termlist_only)
491 wrd->attrSet = VAL_IDXPATH;
499 for (nn = n; nn; nn = nn->parent)
501 if (nn->which == DATA1N_tag)
503 size_t tlen = strlen(nn->u.tag.tag);
504 if (tlen + flen > (sizeof(tag_path_full)-2))
506 memcpy (tag_path_full + flen, nn->u.tag.tag, tlen);
508 tag_path_full[flen++] = '/';
510 else if (nn->which == DATA1N_root)
516 wrd->string = tag_path_full;
518 wrd->attrSet = VAL_IDXPATH;
520 if (p->flagShowRecords)
522 printf("%*s tag=", (level + 1) * 4, "");
523 for (i = 0; i<wrd->length && i < 40; i++)
524 fputc (wrd->string[i], stdout);
535 tag_path_full[flen] = 0;
537 /* Add tag start/end xpath index, only when there is a ! in the apropriate xelm
538 directive, or default xpath indexing is enabled */
539 if (!(do_xpindex = 1 - termlist_only)) {
540 if ((tl = xpath_termlist_by_tagpath(tag_path_full, n))) {
541 for (; tl; tl = tl->next) { if (!tl->att) {do_xpindex = 1;} }
545 (*p->tokenAdd)(wrd); /* index element pag (AKA tag path) */
548 if (use == 1) /* only for the starting tag... */
550 #define MAX_ATTR_COUNT 50
551 data1_termlist *tll[MAX_ATTR_COUNT];
555 /* get termlists for attributes, and find out, if we have to do xpath indexing */
556 for (xp = n->u.tag.attributes; xp; xp = xp->next) {
561 for (xp = n->u.tag.attributes; xp; xp = xp->next) {
563 int do_xpindex = 1 - termlist_only;
565 char attr_tag_path_full[1024];
568 /* this could be cached as well */
569 sprintf (attr_tag_path_full, "@%s/%.*s",
570 xp->name, int_len, tag_path_full);
572 tll[i] = xpath_termlist_by_tagpath(attr_tag_path_full,n);
574 /* if there is a ! in the xelm termlist, or default indexing is on,
575 proceed with xpath idx */
578 for (; tl; tl = tl->next)
587 /* attribute (no value) */
590 wrd->string = xp->name;
591 wrd->length = strlen(xp->name);
597 strlen(xp->name) + strlen(xp->value) < sizeof(comb)-2) {
599 /* attribute value exact */
600 strcpy (comb, xp->name);
602 strcat (comb, xp->value);
607 wrd->length = strlen(comb);
617 for (xp = n->u.tag.attributes; xp; xp = xp->next) {
619 char attr_tag_path_full[1024];
623 sprintf (attr_tag_path_full, "@%s/%.*s",
624 xp->name, int_len, tag_path_full);
628 /* If there is a termlist given (=xelm directive) */
629 for (; tl; tl = tl->next)
632 /* add xpath index for the attribute */
633 index_xpath_attr (attr_tag_path_full, xp->name,
634 xp->value, tl->structure,
638 /* add attribute based index for the attribute */
641 (tl->att->parent->reference);
642 wrd->attrUse = tl->att->locals->local;
643 wrd->reg_type = *tl->structure;
644 wrd->string = xp->value;
645 wrd->length = strlen(xp->value);
651 /* if there was no termlist for the given path,
652 or the termlist didn't have a ! element, index
653 the attribute as "w" */
654 if ((!xpdone) && (!termlist_only))
656 index_xpath_attr (attr_tag_path_full, xp->name,
657 xp->value, "w", p, wrd);
666 static void index_termlist (data1_node *par, data1_node *n,
667 struct recExtractCtrl *p, int level, RecWord *wrd)
669 data1_termlist *tlist = 0;
670 data1_datatype dtype = DATA1K_string;
673 * cycle up towards the root until we find a tag with an att..
674 * this has the effect of indexing locally defined tags with
675 * the attribute of their ancestor in the record.
678 while (!par->u.tag.element)
679 if (!par->parent || !(par=get_parent_tag(p->dh, par->parent)))
681 if (!par || !(tlist = par->u.tag.element->termlists))
683 if (par->u.tag.element->tag)
684 dtype = par->u.tag.element->tag->kind;
686 for (; tlist; tlist = tlist->next)
688 /* consider source */
690 assert(tlist->source);
691 sp_parse(n, wrd, tlist->source);
695 if (p->flagShowRecords)
698 printf("%*sIdx: [%s]", (level + 1) * 4, "",
700 printf("%s:%s [%d] %s",
701 tlist->att->parent->name,
702 tlist->att->name, tlist->att->value,
704 printf (" XData:\"");
705 for (i = 0; i<wrd->length && i < 40; i++)
706 fputc (wrd->string[i], stdout);
708 if (wrd->length > 40)
710 fputc ('\n', stdout);
714 wrd->reg_type = *tlist->structure;
715 wrd->attrSet = (int) (tlist->att->parent->reference);
716 wrd->attrUse = tlist->att->locals->local;
723 static int dumpkeys(data1_node *n, struct recExtractCtrl *p, int level,
726 for (; n; n = n->next)
728 if (p->flagShowRecords) /* display element description to user */
730 if (n->which == DATA1N_root)
732 printf("%*s", level * 4, "");
733 printf("Record type: '%s'\n", n->u.root.type);
735 else if (n->which == DATA1N_tag)
739 printf("%*s", level * 4, "");
740 if (!(e = n->u.tag.element))
741 printf("Local tag: '%s'\n", n->u.tag.tag);
744 printf("Elm: '%s' ", e->name);
747 data1_tag *t = e->tag;
749 printf("TagNam: '%s' ", t->names->name);
752 printf("%s[%d],", t->tagset->name, t->tagset->type);
755 if (t->which == DATA1T_numeric)
756 printf("%d)", t->value.numeric);
758 printf("'%s')", t->value.string);
765 if (n->which == DATA1N_tag)
767 index_termlist (n, n, p, level, wrd);
768 /* index start tag */
769 if (n->root->u.root.absyn)
770 index_xpath (n, p, level, wrd, 1);
774 if (dumpkeys(n->child, p, level + 1, wrd) < 0)
778 if (n->which == DATA1N_data)
780 data1_node *par = get_parent_tag(p->dh, n);
782 if (p->flagShowRecords)
784 printf("%*s", level * 4, "");
786 if (n->u.data.len > 256)
787 printf("'%.170s ... %.70s'\n", n->u.data.data,
788 n->u.data.data + n->u.data.len-70);
789 else if (n->u.data.len > 0)
790 printf("'%.*s'\n", n->u.data.len, n->u.data.data);
796 index_termlist (par, n, p, level, wrd);
798 index_xpath (n, p, level, wrd, 1016);
801 if (n->which == DATA1N_tag)
804 index_xpath (n, p, level, wrd, 2);
807 if (p->flagShowRecords && n->which == DATA1N_root)
809 printf("%*s-------------\n\n", level * 4, "");
815 int grs_extract_tree(struct recExtractCtrl *p, data1_node *n)
818 int oidtmp[OID_SIZE];
821 oe.proto = PROTO_Z3950;
822 oe.oclass = CLASS_SCHEMA;
825 oe.value = n->u.root.absyn->reference;
827 if ((oid_ent_to_oid (&oe, oidtmp)))
828 (*p->schemaAdd)(p, oidtmp);
832 return dumpkeys(n, p, 0, &wrd);
835 static int grs_extract_sub(void *clientData, struct recExtractCtrl *p,
837 data1_node *(*grs_read)(struct grs_read_info *))
840 struct grs_read_info gri;
842 int oidtmp[OID_SIZE];
845 gri.readf = p->readf;
846 gri.seekf = p->seekf;
847 gri.tellf = p->tellf;
850 gri.offset = p->offset;
853 gri.clientData = clientData;
855 n = (*grs_read)(&gri);
857 return RECCTRL_EXTRACT_EOF;
858 oe.proto = PROTO_Z3950;
859 oe.oclass = CLASS_SCHEMA;
861 if (!n->u.root.absyn)
862 return RECCTRL_EXTRACT_ERROR;
866 oe.value = n->u.root.absyn->reference;
867 if ((oid_ent_to_oid (&oe, oidtmp)))
868 (*p->schemaAdd)(p, oidtmp);
870 data1_concat_text(p->dh, mem, n);
872 /* ensure our data1 tree is UTF-8 */
873 data1_iconv (p->dh, mem, n, "UTF-8", data1_get_encoding(p->dh, n));
876 data1_pr_tree (p->dh, n, stdout);
880 if (dumpkeys(n, p, 0, &wrd) < 0)
882 data1_free_tree(p->dh, n);
883 return RECCTRL_EXTRACT_ERROR_GENERIC;
885 data1_free_tree(p->dh, n);
886 return RECCTRL_EXTRACT_OK;
889 int zebra_grs_extract(void *clientData, struct recExtractCtrl *p,
890 data1_node *(*grs_read)(struct grs_read_info *))
893 NMEM mem = nmem_create ();
894 ret = grs_extract_sub(clientData, p, mem, grs_read);
900 * Return: -1: Nothing done. 0: Ok. >0: Bib-1 diagnostic.
902 static int process_comp(data1_handle dh, data1_node *n, Z_RecordComposition *c,
903 char **addinfo, ODR o)
905 data1_esetname *eset;
911 case Z_RecordComp_simple:
912 if (c->u.simple->which != Z_ElementSetNames_generic)
913 return 26; /* only generic form supported. Fix this later */
914 if (!(eset = data1_getesetbyname(dh, n->u.root.absyn,
915 c->u.simple->u.generic)))
917 yaz_log(YLOG_LOG, "Unknown esetname '%s'", c->u.simple->u.generic);
918 *addinfo = odr_strdup(o, c->u.simple->u.generic);
919 return 25; /* invalid esetname */
921 yaz_log(YLOG_DEBUG, "Esetname '%s' in simple compspec",
922 c->u.simple->u.generic);
925 case Z_RecordComp_complex:
926 if (c->u.complex->generic)
928 /* insert check for schema */
929 if ((p = c->u.complex->generic->elementSpec))
933 case Z_ElementSpec_elementSetName:
935 data1_getesetbyname(dh, n->u.root.absyn,
936 p->u.elementSetName)))
938 yaz_log(YLOG_DEBUG, "Unknown esetname '%s'",
939 p->u.elementSetName);
940 *addinfo = odr_strdup(o, p->u.elementSetName);
941 return 25; /* invalid esetname */
943 yaz_log(YLOG_DEBUG, "Esetname '%s' in complex compspec",
944 p->u.elementSetName);
947 case Z_ElementSpec_externalSpec:
948 if (p->u.externalSpec->which == Z_External_espec1)
950 yaz_log(YLOG_DEBUG, "Got Espec-1");
951 espec = p->u.externalSpec-> u.espec1;
955 yaz_log(YLOG_LOG, "Unknown external espec.");
956 return 25; /* bad. what is proper diagnostic? */
967 yaz_log(YLOG_DEBUG, "Element: Espec-1 match");
968 return data1_doespec1(dh, n, espec);
972 yaz_log(YLOG_DEBUG, "Element: all match");
977 /* Add Zebra info in separate namespace ...
980 <metadata xmlns="http://www.indexdata.dk/zebra/">
982 <localnumber>447</localnumber>
983 <filename>records/genera.xml</filename>
988 static void zebra_xml_metadata (struct recRetrieveCtrl *p, data1_node *top,
991 const char *idzebra_ns[3];
992 const char *i2 = "\n ";
993 const char *i4 = "\n ";
996 idzebra_ns[0] = "xmlns";
997 idzebra_ns[1] = "http://www.indexdata.dk/zebra/";
1000 data1_mk_text (p->dh, mem, i2, top);
1002 n = data1_mk_tag (p->dh, mem, "idzebra", idzebra_ns, top);
1004 data1_mk_text (p->dh, mem, "\n", top);
1006 data1_mk_text (p->dh, mem, i4, n);
1008 data1_mk_tag_data_int (p->dh, n, "size", p->recordSize, mem);
1012 data1_mk_text (p->dh, mem, i4, n);
1013 data1_mk_tag_data_int (p->dh, n, "score", p->score, mem);
1015 data1_mk_text (p->dh, mem, i4, n);
1016 data1_mk_tag_data_zint (p->dh, n, "localnumber", p->localno, mem);
1019 data1_mk_text (p->dh, mem, i4, n);
1020 data1_mk_tag_data_text(p->dh, n, "filename", p->fname, mem);
1022 data1_mk_text (p->dh, mem, i2, n);
1025 int zebra_grs_retrieve(void *clientData, struct recRetrieveCtrl *p,
1026 data1_node *(*grs_read)(struct grs_read_info *))
1028 data1_node *node = 0, *onode = 0, *top;
1031 int res, selected = 0;
1033 struct grs_read_info gri;
1034 const char *tagname;
1036 int requested_schema = VAL_NONE;
1037 data1_marctab *marctab;
1040 mem = nmem_create();
1041 gri.readf = p->readf;
1042 gri.seekf = p->seekf;
1043 gri.tellf = p->tellf;
1049 gri.clientData = clientData;
1051 yaz_log(YLOG_DEBUG, "grs_retrieve");
1052 node = (*grs_read)(&gri);
1059 data1_concat_text(p->dh, mem, node);
1062 data1_pr_tree (p->dh, node, stdout);
1064 top = data1_get_root_tag (p->dh, node);
1066 yaz_log(YLOG_DEBUG, "grs_retrieve: size");
1067 tagname = data1_systag_lookup(node->u.root.absyn, "size", "size");
1069 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1071 dnew->u.data.what = DATA1I_text;
1072 dnew->u.data.data = dnew->lbuf;
1073 sprintf(dnew->u.data.data, "%d", p->recordSize);
1074 dnew->u.data.len = strlen(dnew->u.data.data);
1077 tagname = data1_systag_lookup(node->u.root.absyn, "rank", "rank");
1078 if (tagname && p->score >= 0 &&
1079 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1081 yaz_log(YLOG_DEBUG, "grs_retrieve: %s", tagname);
1082 dnew->u.data.what = DATA1I_num;
1083 dnew->u.data.data = dnew->lbuf;
1084 sprintf(dnew->u.data.data, "%d", p->score);
1085 dnew->u.data.len = strlen(dnew->u.data.data);
1088 tagname = data1_systag_lookup(node->u.root.absyn, "sysno",
1089 "localControlNumber");
1090 if (tagname && p->localno > 0 &&
1091 (dnew = data1_mk_tag_data_wd(p->dh, top, tagname, mem)))
1093 yaz_log(YLOG_DEBUG, "grs_retrieve: %s", tagname);
1094 dnew->u.data.what = DATA1I_text;
1095 dnew->u.data.data = dnew->lbuf;
1097 sprintf(dnew->u.data.data, ZINT_FORMAT, p->localno);
1098 dnew->u.data.len = strlen(dnew->u.data.data);
1101 if (p->input_format == VAL_TEXT_XML)
1102 zebra_xml_metadata (p, top, mem);
1105 data1_pr_tree (p->dh, node, stdout);
1107 if (p->comp && p->comp->which == Z_RecordComp_complex &&
1108 p->comp->u.complex->generic &&
1109 p->comp->u.complex->generic->which == Z_Schema_oid &&
1110 p->comp->u.complex->generic->schema.oid)
1112 oident *oe = oid_getentbyoid (p->comp->u.complex->generic->schema.oid);
1114 requested_schema = oe->value;
1116 /* If schema has been specified, map if possible, then check that
1117 * we got the right one
1119 if (requested_schema != VAL_NONE)
1121 yaz_log(YLOG_DEBUG, "grs_retrieve: schema mapping");
1122 for (map = node->u.root.absyn->maptabs; map; map = map->next)
1124 if (map->target_absyn_ref == requested_schema)
1127 if (!(node = data1_map_record(p->dh, onode, map, mem)))
1136 if (node->u.root.absyn &&
1137 requested_schema != node->u.root.absyn->reference)
1139 p->diagnostic = 238;
1145 * Does the requested format match a known syntax-mapping? (this reflects
1146 * the overlap of schema and formatting which is inherent in the MARC
1149 yaz_log(YLOG_DEBUG, "grs_retrieve: syntax mapping");
1150 if (node->u.root.absyn)
1151 for (map = node->u.root.absyn->maptabs; map; map = map->next)
1153 if (map->target_absyn_ref == p->input_format)
1156 if (!(node = data1_map_record(p->dh, onode, map, mem)))
1165 yaz_log(YLOG_DEBUG, "grs_retrieve: schemaIdentifier");
1166 if (node->u.root.absyn &&
1167 node->u.root.absyn->reference != VAL_NONE &&
1168 p->input_format == VAL_GRS1)
1172 int oidtmp[OID_SIZE];
1174 oe.proto = PROTO_Z3950;
1175 oe.oclass = CLASS_SCHEMA;
1176 oe.value = node->u.root.absyn->reference;
1178 if ((oid = oid_ent_to_oid (&oe, oidtmp)))
1181 data1_handle dh = p->dh;
1185 for (ii = oid; *ii >= 0; ii++)
1189 sprintf(p, "%d", *ii);
1192 if ((dnew = data1_mk_tag_data_wd(dh, top,
1193 "schemaIdentifier", mem)))
1195 dnew->u.data.what = DATA1I_oid;
1196 dnew->u.data.data = (char *) nmem_malloc(mem, p - tmp);
1197 memcpy(dnew->u.data.data, tmp, p - tmp);
1198 dnew->u.data.len = p - tmp;
1203 yaz_log(YLOG_DEBUG, "grs_retrieve: element spec");
1204 if (p->comp && (res = process_comp(p->dh, node, p->comp, &p->addinfo,
1207 p->diagnostic = res;
1209 data1_free_tree(p->dh, onode);
1210 data1_free_tree(p->dh, node);
1214 else if (p->comp && !res)
1218 data1_pr_tree (p->dh, node, stdout);
1220 yaz_log(YLOG_DEBUG, "grs_retrieve: transfer syntax mapping");
1221 switch (p->output_format = (p->input_format != VAL_NONE ?
1222 p->input_format : VAL_SUTRS))
1226 data1_pr_tree (p->dh, node, stdout);
1228 /* default output encoding for XML is UTF-8 */
1229 data1_iconv (p->dh, mem, node,
1230 p->encoding ? p->encoding : "UTF-8",
1231 data1_get_encoding(p->dh, node));
1233 if (!(p->rec_buf = data1_nodetoidsgml(p->dh, node, selected,
1235 p->diagnostic = 238;
1238 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1239 memcpy (new_buf, p->rec_buf, p->rec_len);
1240 p->rec_buf = new_buf;
1244 data1_iconv (p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1246 if (!(p->rec_buf = data1_nodetogr(p->dh, node, selected,
1248 p->diagnostic = 238; /* not available in requested syntax */
1250 p->rec_len = (size_t) (-1);
1253 /* ensure our data1 tree is UTF-8 */
1254 data1_iconv (p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1256 if (!(p->rec_buf = data1_nodetoexplain(p->dh, node, selected,
1258 p->diagnostic = 238;
1260 p->rec_len = (size_t) (-1);
1263 /* ensure our data1 tree is UTF-8 */
1264 data1_iconv (p->dh, mem, node, "UTF-8", data1_get_encoding(p->dh, node));
1265 if (!(p->rec_buf = data1_nodetosummary(p->dh, node, selected,
1267 p->diagnostic = 238;
1269 p->rec_len = (size_t) (-1);
1273 data1_iconv (p->dh, mem, node, p->encoding,
1274 data1_get_encoding(p->dh, node));
1275 if (!(p->rec_buf = data1_nodetobuf(p->dh, node, selected,
1277 p->diagnostic = 238;
1280 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1281 memcpy (new_buf, p->rec_buf, p->rec_len);
1282 p->rec_buf = new_buf;
1287 data1_iconv (p->dh, mem, node, p->encoding,
1288 data1_get_encoding(p->dh, node));
1289 if (!(p->rec_buf = data1_nodetosoif(p->dh, node, selected,
1291 p->diagnostic = 238;
1294 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1295 memcpy (new_buf, p->rec_buf, p->rec_len);
1296 p->rec_buf = new_buf;
1300 if (!node->u.root.absyn)
1302 p->diagnostic = 238;
1305 for (marctab = node->u.root.absyn->marc; marctab;
1306 marctab = marctab->next)
1307 if (marctab->reference == p->input_format)
1311 p->diagnostic = 238;
1315 data1_iconv (p->dh, mem, node, p->encoding,
1316 data1_get_encoding(p->dh, node));
1317 if (!(p->rec_buf = data1_nodetomarc(p->dh, marctab, node,
1318 selected, &p->rec_len)))
1319 p->diagnostic = 238;
1322 char *new_buf = (char*) odr_malloc (p->odr, p->rec_len);
1323 memcpy (new_buf, p->rec_buf, p->rec_len);
1324 p->rec_buf = new_buf;
1328 data1_free_tree(p->dh, node);
1330 data1_free_tree(p->dh, onode);