source: trunk/gsdl/packages/yaz/retrieval/d1_map.c@ 1343

Last change on this file since 1343 was 1343, checked in by johnmcp, 24 years ago

Added the YAZ toolkit source to the packages directory (for z39.50 stuff)

  • Property svn:keywords set to Author Date Id Revision
File size: 9.1 KB
Line 
1/*
2 * Copyright (c) 1995-1999, Index Data.
3 * See the file LICENSE for details.
4 * Sebastian Hammer, Adam Dickmeiss
5 *
6 * $Log$
7 * Revision 1.1 2000/08/03 03:11:33 johnmcp
8 * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
9 *
10 * Revision 1.17 1999/11/30 13:47:12 adam
11 * Improved installation. Moved header files to include/yaz.
12 *
13 * Revision 1.16 1999/10/21 12:06:29 adam
14 * Retrieval module no longer uses ctype.h - functions.
15 *
16 * Revision 1.15 1999/08/27 09:40:32 adam
17 * Renamed logf function to yaz_log. Removed VC++ project files.
18 *
19 * Revision 1.14 1998/10/13 16:09:50 adam
20 * Added support for arbitrary OID's for tagsets, schemas and attribute sets.
21 * Added support for multiple attribute set references and tagset references
22 * from an abstract syntax file.
23 * Fixed many bad logs-calls in routines that read the various
24 * specifications regarding data1 (*.abs,*.att,...) and made the messages
25 * consistent whenever possible.
26 * Added extra 'lineno' argument to function readconf_line.
27 *
28 * Revision 1.13 1998/02/11 11:53:35 adam
29 * Changed code so that it compiles as C++.
30 *
31 * Revision 1.12 1997/11/18 09:51:09 adam
32 * Removed element num_children from data1_node. Minor changes in
33 * data1 to Explain.
34 *
35 * Revision 1.11 1997/09/17 12:10:36 adam
36 * YAZ version 1.4.
37 *
38 * Revision 1.10 1997/09/05 09:50:56 adam
39 * Removed global data1_tabpath - uses data1_get_tabpath() instead.
40 *
41 * Revision 1.9 1996/06/10 08:56:02 quinn
42 * Work on Summary.
43 *
44 * Revision 1.8 1996/05/01 12:45:31 quinn
45 * Support use of local tag names in abs file.
46 *
47 * Revision 1.7 1995/12/13 13:44:31 quinn
48 * Modified Data1-system to use nmem
49 *
50 * Revision 1.6 1995/12/12 16:37:08 quinn
51 * Added destroy element to data1_node.
52 *
53 * Revision 1.5 1995/12/12 14:11:31 quinn
54 * More work on the large-record problem.
55 *
56 * Revision 1.4 1995/12/11 15:22:37 quinn
57 * Added last_child field to the node.
58 * Rewrote schema-mapping.
59 *
60 * Revision 1.3 1995/11/01 16:34:56 quinn
61 * Making data1 look for tables in data1_tabpath
62 *
63 * Revision 1.2 1995/11/01 13:54:46 quinn
64 * Minor adjustments
65 *
66 * Revision 1.1 1995/11/01 11:56:08 quinn
67 * Added Retrieval (data management) functions en masse.
68 *
69 *
70 */
71
72#include <stdio.h>
73#include <stdlib.h>
74#include <string.h>
75
76#include <yaz/oid.h>
77#include <yaz/log.h>
78#include <yaz/readconf.h>
79#include <yaz/tpath.h>
80#include <yaz/data1.h>
81#include <yaz/d1_map.h>
82
83data1_maptab *data1_read_maptab (data1_handle dh, const char *file)
84{
85 NMEM mem = data1_nmem_get (dh);
86 data1_maptab *res = (data1_maptab *)nmem_malloc(mem, sizeof(*res));
87 FILE *f;
88 int lineno = 0;
89 int argc;
90 char *argv[50], line[512];
91 data1_mapunit **mapp;
92 int local_numeric = 0;
93
94 if (!(f = yaz_path_fopen(data1_get_tabpath(dh), file, "r")))
95 {
96 yaz_log(LOG_WARN|LOG_ERRNO, "%s", file);
97 return 0;
98 }
99
100 res->name = 0;
101 res->target_absyn_ref = VAL_NONE;
102 res->map = 0;
103 mapp = &res->map;
104 res->next = 0;
105
106 while ((argc = readconf_line(f, &lineno, line, 512, argv, 50)))
107 if (!strcmp(argv[0], "targetref"))
108 {
109 if (argc != 2)
110 {
111 yaz_log(LOG_WARN, "%s:%d: Bad # args for targetref",
112 file, lineno);
113 continue;
114 }
115 if ((res->target_absyn_ref = oid_getvalbyname(argv[1]))
116 == VAL_NONE)
117 {
118 yaz_log(LOG_WARN, "%s:%d: Unknown reference '%s'",
119 file, lineno, argv[1]);
120 continue;
121 }
122 }
123 else if (!strcmp(argv[0], "targetname"))
124 {
125 if (argc != 2)
126 {
127 yaz_log(LOG_WARN, "%s:%d: Bad # args for targetname",
128 file, lineno);
129 continue;
130 }
131 res->target_absyn_name =
132 (char *)nmem_malloc(mem, strlen(argv[1])+1);
133 strcpy(res->target_absyn_name, argv[1]);
134 }
135 else if (!yaz_matchstr(argv[0], "localnumeric"))
136 local_numeric = 1;
137 else if (!strcmp(argv[0], "name"))
138 {
139 if (argc != 2)
140 {
141 yaz_log(LOG_WARN, "%s:%d: Bad # args for name", file, lineno);
142 continue;
143 }
144 res->name = (char *)nmem_malloc(mem, strlen(argv[1])+1);
145 strcpy(res->name, argv[1]);
146 }
147 else if (!strcmp(argv[0], "map"))
148 {
149 data1_maptag **mtp;
150 char *ep, *path = argv[2];
151
152 if (argc < 3)
153 {
154 yaz_log(LOG_WARN, "%s:%d: Bad # of args for map",
155 file, lineno);
156 continue;
157 }
158 *mapp = (data1_mapunit *)nmem_malloc(mem, sizeof(**mapp));
159 (*mapp)->next = 0;
160 if (argc > 3 && !data1_matchstr(argv[3], "nodata"))
161 (*mapp)->no_data = 1;
162 else
163 (*mapp)->no_data = 0;
164 (*mapp)->source_element_name =
165 (char *)nmem_malloc(mem, strlen(argv[1])+1);
166 strcpy((*mapp)->source_element_name, argv[1]);
167 mtp = &(*mapp)->target_path;
168 if (*path == '/')
169 path++;
170 for (ep = strchr(path, '/'); path; (void)((path = ep) &&
171 (ep = strchr(path, '/'))))
172 {
173 int type, np;
174 char valstr[512], parm[512];
175
176 if (ep)
177 ep++;
178 if ((np = sscanf(path, "(%d,%[^)]):%[^/]", &type, valstr,
179 parm)) < 2)
180 {
181 yaz_log(LOG_WARN, "%s:%d: Syntax error in map "
182 "directive: %s", file, lineno, argv[2]);
183 fclose(f);
184 return 0;
185 }
186 *mtp = (data1_maptag *)nmem_malloc(mem, sizeof(**mtp));
187 (*mtp)->next = 0;
188 (*mtp)->type = type;
189 if (np > 2 && !data1_matchstr(parm, "new"))
190 (*mtp)->new_field = 1;
191 else
192 (*mtp)->new_field = 0;
193 if ((type != 3 || local_numeric) && d1_isdigit(*valstr))
194 {
195 (*mtp)->which = D1_MAPTAG_numeric;
196 (*mtp)->value.numeric = atoi(valstr);
197 }
198 else
199 {
200 (*mtp)->which = D1_MAPTAG_string;
201 (*mtp)->value.string =
202 (char *)nmem_malloc(mem, strlen(valstr)+1);
203 strcpy((*mtp)->value.string, valstr);
204 }
205 mtp = &(*mtp)->next;
206 }
207 mapp = &(*mapp)->next;
208 }
209 else
210 yaz_log(LOG_WARN, "%s:%d: Unknown directive '%s'",
211 file, lineno, argv[0]);
212
213 fclose(f);
214 return res;
215}
216
217/*
218 * Locate node with given elementname.
219 * NOTE: This is stupid - we don't find repeats this way.
220 */
221static data1_node *find_node(data1_node *p, char *elementname)
222{
223 data1_node *c, *r;
224
225 for (c = p->child; c; c = c->next)
226 if (c->which == DATA1N_tag && c->u.tag.element &&
227 !data1_matchstr(c->u.tag.element->name, elementname))
228 return c;
229 else if ((r = find_node(c, elementname)))
230 return r;
231 return 0;
232}
233
234/*
235 * See if the node n is equivalent to the tag t.
236 */
237static int tagmatch(data1_node *n, data1_maptag *t)
238{
239 if (n->which != DATA1N_tag)
240 return 0;
241 if (n->u.tag.element)
242 {
243 if (n->u.tag.element->tag->tagset)
244 {
245 if (n->u.tag.element->tag->tagset->type != t->type)
246 return 0;
247 }
248 else if (t->type != 3)
249 return 0;
250 if (n->u.tag.element->tag->which == DATA1T_numeric)
251 {
252 if (t->which != D1_MAPTAG_numeric)
253 return 0;
254 if (n->u.tag.element->tag->value.numeric != t->value.numeric)
255 return 0;
256 }
257 else
258 {
259 if (t->which != D1_MAPTAG_string)
260 return 0;
261 if (data1_matchstr(n->u.tag.element->tag->value.string,
262 t->value.string))
263 return 0;
264 }
265 }
266 else /* local tag */
267 {
268 char str[10];
269
270 if (t->type != 3)
271 return 0;
272 if (t->which == D1_MAPTAG_numeric)
273 sprintf(str, "%d", t->value.numeric);
274 else
275 strcpy(str, t->value.string);
276 if (data1_matchstr(n->u.tag.tag, str))
277 return 0;
278 }
279 return 1;
280}
281
282static int map_children(data1_handle dh, data1_node *n, data1_maptab *map,
283 data1_node *res, NMEM mem)
284{
285 data1_node *c;
286 data1_mapunit *m;
287 /*
288 * locate each source element in turn.
289 */
290 for (c = n->child; c; c = c->next)
291 if (c->which == DATA1N_tag && c->u.tag.element)
292 {
293 for (m = map->map; m; m = m->next)
294 {
295 if (!data1_matchstr(m->source_element_name,
296 c->u.tag.element->name))
297 {
298 data1_node *pn = res;
299 data1_node *cur = pn->last_child;
300 data1_maptag *mt;
301
302 /*
303 * process the target path specification.
304 */
305 for (mt = m->target_path; mt; mt = mt->next)
306 {
307 if (!cur || mt->new_field || !tagmatch(cur, mt))
308 {
309 cur = data1_mk_node (dh, mem);
310 cur->which = DATA1N_tag;
311 cur->u.tag.element = 0;
312 cur->u.tag.tag = mt->value.string;
313 cur->u.tag.node_selected = 0;
314 cur->parent = pn;
315 cur->root = pn->root;
316 if (!pn->child)
317 pn->child = cur;
318 if (pn->last_child)
319 pn->last_child->next = cur;
320 pn->last_child = cur;
321 }
322
323 if (mt->next)
324 pn = cur;
325 else if (!m->no_data)
326 {
327 cur->child = c->child;
328 cur->last_child = c->last_child;
329 c->child = 0;
330 c->last_child = 0;
331 }
332 }
333 break;
334 }
335 }
336 if (map_children(dh, c, map, res, mem) < 0)
337 return -1;
338 }
339 return 0;
340}
341
342/*
343 * Create a (possibly lossy) copy of the given record based on the
344 * table. The new copy will refer back to the data of the original record,
345 * which should not be discarded during the lifetime of the copy.
346 */
347data1_node *data1_map_record (data1_handle dh, data1_node *n,
348 data1_maptab *map, NMEM m)
349{
350 data1_node *res = data1_mk_node(dh, m);
351
352 res->which = DATA1N_root;
353 res->u.root.type = map->target_absyn_name;
354 if (!(res->u.root.absyn = data1_get_absyn(dh, map->target_absyn_name)))
355 {
356 yaz_log(LOG_WARN, "%s: Failed to load target absyn '%s'",
357 map->name, map->target_absyn_name);
358 }
359 res->parent = 0;
360 res->root = res;
361
362 if (map_children(dh, n, map, res, m) < 0)
363 {
364 data1_free_tree(dh, res);
365 return 0;
366 }
367 return res;
368}
369
Note: See TracBrowser for help on using the repository browser.