IDZEBRA  2.2.7
d1_map.c
Go to the documentation of this file.
1 /* This file is part of the Zebra server.
2  Copyright (C) Index Data
3 
4 Zebra is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8 
9 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 
18 */
19 
20 #if HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include <yaz/log.h>
28 #include <yaz/oid_db.h>
29 #include <yaz/snprintf.h>
30 #include <yaz/readconf.h>
31 #include <yaz/tpath.h>
32 #include <d1_absyn.h>
33 
35 {
36  int no_data;
37  int no_chop;
41 };
42 
44 {
45  NMEM mem = data1_nmem_get(dh);
46  data1_maptab *res = (data1_maptab *)nmem_malloc(mem, sizeof(*res));
47  FILE *f;
48  int lineno = 0;
49  int argc;
50  char *argv[50], line[512];
51  data1_mapunit **mapp;
52  int local_numeric = 0;
53 
54  if (!(f = data1_path_fopen(dh, file, "r")))
55  return 0;
56 
57  res->name = 0;
58  res->oid = 0;
59  res->map = 0;
60  mapp = &res->map;
61  res->next = 0;
62 
63  while ((argc = readconf_line(f, &lineno, line, 512, argv, 50)))
64  if (!strcmp(argv[0], "targetref"))
65  {
66  if (argc != 2)
67  {
68  yaz_log(YLOG_WARN, "%s:%d: Bad # args for targetref",
69  file, lineno);
70  continue;
71  }
72  res->oid = yaz_string_to_oid_nmem(yaz_oid_std(),
73  CLASS_RECSYN, argv[1], mem);
74  if (!res->oid)
75  {
76  yaz_log(YLOG_WARN, "%s:%d: Unknown reference '%s'",
77  file, lineno, argv[1]);
78  continue;
79  }
80  }
81  else if (!strcmp(argv[0], "targetname"))
82  {
83  if (argc != 2)
84  {
85  yaz_log(YLOG_WARN, "%s:%d: Bad # args for targetname",
86  file, lineno);
87  continue;
88  }
89  res->target_absyn_name = nmem_strdup(mem, argv[1]);
90  }
91  else if (!yaz_matchstr(argv[0], "localnumeric"))
92  local_numeric = 1;
93  else if (!strcmp(argv[0], "name"))
94  {
95  if (argc != 2)
96  {
97  yaz_log(YLOG_WARN, "%s:%d: Bad # args for name", file, lineno);
98  continue;
99  }
100  res->name = nmem_strdup(mem, argv[1]);
101  }
102  else if (!strcmp(argv[0], "map"))
103  {
104  data1_maptag **mtp;
105  char *ep, *path = argv[2];
106 
107  if (argc < 3)
108  {
109  yaz_log(YLOG_WARN, "%s:%d: Bad # of args for map",
110  file, lineno);
111  continue;
112  }
113  *mapp = (data1_mapunit *)nmem_malloc(mem, sizeof(**mapp));
114  (*mapp)->next = 0;
115  if (argc > 3 && !data1_matchstr(argv[3], "nodata"))
116  (*mapp)->no_data = 1;
117  else
118  (*mapp)->no_data = 0;
119  if (argc > 3 && !data1_matchstr(argv[3], "nochop"))
120  (*mapp)->no_chop = 1;
121  else
122  (*mapp)->no_chop = 0;
123  (*mapp)->source_element_name = nmem_strdup(mem, argv[1]);
124  mtp = &(*mapp)->target_path;
125  if (*path == '/')
126  path++;
127  for (ep = strchr(path, '/'); path; (void)((path = ep) &&
128  (ep = strchr(path, '/'))))
129  {
130  int type, np;
131  char valstr[512], parm[512];
132 
133  if (ep)
134  ep++;
135  if ((np = sscanf(path, "(%d,%511[^)]):%511[^/]", &type, valstr,
136  parm)) < 2)
137  {
138  yaz_log(YLOG_WARN, "%s:%d: Syntax error in map "
139  "directive: %s", file, lineno, argv[2]);
140  fclose(f);
141  return 0;
142  }
143  *mtp = (data1_maptag *)nmem_malloc(mem, sizeof(**mtp));
144  (*mtp)->next = 0;
145  (*mtp)->type = type;
146  if (np > 2 && !data1_matchstr(parm, "new"))
147  (*mtp)->new_field = 1;
148  else
149  (*mtp)->new_field = 0;
150  if ((type != 3 || local_numeric) && d1_isdigit(*valstr))
151  {
152  (*mtp)->which = D1_MAPTAG_numeric;
153  (*mtp)->value.numeric = atoi(valstr);
154  }
155  else
156  {
157  (*mtp)->which = D1_MAPTAG_string;
158  (*mtp)->value.string = nmem_strdup(mem, valstr);
159  }
160  mtp = &(*mtp)->next;
161  }
162  mapp = &(*mapp)->next;
163  }
164  else
165  yaz_log(YLOG_WARN, "%s:%d: Unknown directive '%s'",
166  file, lineno, argv[0]);
167 
168  fclose(f);
169  return res;
170 }
171 
172 /*
173  * See if the node n is equivalent to the tag t.
174  */
175 static int tagmatch(data1_node *n, data1_maptag *t)
176 {
177  if (n->which != DATA1N_tag)
178  return 0;
179  if (n->u.tag.element)
180  {
181  if (n->u.tag.element->tag->tagset)
182  {
183  if (n->u.tag.element->tag->tagset->type != t->type)
184  return 0;
185  }
186  else if (t->type != 3)
187  return 0;
188  if (n->u.tag.element->tag->which == DATA1T_numeric)
189  {
190  if (t->which != D1_MAPTAG_numeric)
191  return 0;
192  if (n->u.tag.element->tag->value.numeric != t->value.numeric)
193  return 0;
194  }
195  else
196  {
197  if (t->which != D1_MAPTAG_string)
198  return 0;
199  if (data1_matchstr(n->u.tag.element->tag->value.string,
200  t->value.string))
201  return 0;
202  }
203  }
204  else /* local tag */
205  {
206  if (t->type != 3)
207  return 0;
208  if (t->which == D1_MAPTAG_numeric)
209  {
210  char str[16];
211  yaz_snprintf(str, sizeof(str), "%d", t->value.numeric);
212  if (data1_matchstr(n->u.tag.tag, str))
213  return 0;
214  }
215  else
216  {
217  if (data1_matchstr(n->u.tag.tag, t->value.string))
218  return 0;
219  }
220  }
221  return 1;
222 }
223 
225  data1_node **last, NMEM mem,
226  data1_node *parent)
227 {
228  data1_node *first = 0;
229  data1_node **m = &first;
230 
231  for (; n; n = n->next)
232  {
233  *last = *m = (data1_node *) nmem_malloc(mem, sizeof(**m));
234  memcpy(*m, n, sizeof(**m));
235 
236  (*m)->parent = parent;
237  (*m)->root = parent->root;
238  (*m)->child = dup_child(dh, n->child, &(*m)->last_child, mem, *m);
239  m = &(*m)->next;
240  }
241  *m = 0;
242  return first;
243 }
244 
246  data1_node *res, NMEM mem)
247 {
248  data1_node *c;
249  data1_mapunit *m;
250  /*
251  * locate each source element in turn.
252  */
253  for (c = n->child; c; c = c->next)
254  if (c->which == DATA1N_tag && c->u.tag.element)
255  {
256  for (m = map->map; m; m = m->next)
257  {
259  c->u.tag.element->name))
260  {
261  data1_node *pn = res;
262  data1_node *cur = pn->last_child;
263  data1_maptag *mt;
264 
265  /*
266  * process the target path specification.
267  */
268  for (mt = m->target_path; mt; mt = mt->next)
269  {
270  if (!cur || mt->new_field || !tagmatch(cur, mt))
271  {
272  if (mt->which == D1_MAPTAG_string)
273  {
274  cur = data1_mk_node2(dh, mem, DATA1N_tag, pn);
275  cur->u.tag.tag = mt->value.string;
276  }
277  else if (mt->which == D1_MAPTAG_numeric)
278  {
279  data1_tag *tag =
281  dh,
282  pn->root->u.root.absyn->tagset,
283  mt->type,
284  mt->value.numeric);
285 
286  if (tag && tag->names->name)
287  {
288  cur = data1_mk_tag(
289  dh, mem, tag->names->name, 0, pn);
290 
291  }
292  }
293  }
294 
295  if (mt->next)
296  pn = cur;
297  else if (!m->no_data)
298  {
299  cur->child =
300  dup_child(dh, c->child,
301  &cur->last_child, mem, cur);
302  if (!m->no_chop)
303  {
304  data1_concat_text(dh, mem, cur->child);
305  data1_chop_text(dh, mem, cur->child);
306  }
307  }
308  }
309  }
310  }
311  if (map_children(dh, c, map, res, mem) < 0)
312  return -1;
313  }
314  return 0;
315 }
316 
317 /*
318  * Create a (possibly lossy) copy of the given record based on the
319  * table. The new copy will refer back to the data of the original record,
320  * which should not be discarded during the lifetime of the copy.
321  */
323  data1_maptab *map, NMEM m)
324 {
325  data1_node *res1, *res = data1_mk_node2(dh, m, DATA1N_root, 0);
326 
327  res->which = DATA1N_root;
328  res->u.root.type = map->target_absyn_name;
329  if (!(res->u.root.absyn = data1_get_absyn(dh, map->target_absyn_name,
331  {
332  yaz_log(YLOG_WARN, "%s: Failed to load target absyn '%s'",
333  map->name, map->target_absyn_name);
334  }
335  n = n->child;
336  if (!n)
337  return 0;
338  res1 = data1_mk_tag(dh, m, map->target_absyn_name, 0, res);
339  while (n && n->which != DATA1N_tag)
340  n = n->next;
341  if (map_children(dh, n, map, res1, m) < 0)
342  return 0;
343  return res;
344 }
345 
346 /*
347  * Local variables:
348  * c-basic-offset: 4
349  * c-file-style: "Stroustrup"
350  * indent-tabs-mode: nil
351  * End:
352  * vim: shiftwidth=4 tabstop=8 expandtab
353  */
354 
data1_maptab * data1_read_maptab(data1_handle dh, const char *file)
Definition: d1_map.c:43
static data1_node * dup_child(data1_handle dh, data1_node *n, data1_node **last, NMEM mem, data1_node *parent)
Definition: d1_map.c:224
static int tagmatch(data1_node *n, data1_maptag *t)
Definition: d1_map.c:175
data1_node * data1_map_record(data1_handle dh, data1_node *n, data1_maptab *map, NMEM m)
Definition: d1_map.c:322
static int map_children(data1_handle dh, data1_node *n, data1_maptab *map, data1_node *res, NMEM mem)
Definition: d1_map.c:245
data1_node * data1_mk_tag(data1_handle dh, NMEM nmem, const char *tag, const char **attr, data1_node *at)
Definition: d1_read.c:295
data1_absyn * data1_get_absyn(data1_handle dh, const char *name, enum DATA1_XPATH_INDEXING en)
Definition: d1_absyn.c:231
#define D1_MAPTAG_string
Definition: data1.h:90
void data1_concat_text(data1_handle dh, NMEM m, data1_node *n)
Definition: d1_read.c:1107
FILE * data1_path_fopen(data1_handle dh, const char *file, const char *mode)
Definition: d1_handle.c:147
data1_tag * data1_gettagbynum(data1_handle dh, data1_tagset *s, int type, int value)
Definition: d1_tagset.c:64
NMEM data1_nmem_get(data1_handle dh)
Definition: d1_handle.c:66
#define data1_matchstr(s1, s2)
Definition: data1.h:36
#define DATA1N_tag
Definition: data1.h:276
#define DATA1N_root
Definition: data1.h:274
#define d1_isdigit(c)
Definition: data1.h:32
data1_node * data1_mk_node2(data1_handle dh, NMEM m, int type, data1_node *parent)
Definition: d1_read.c:146
void data1_chop_text(data1_handle dh, NMEM m, data1_node *n)
Definition: d1_read.c:1078
@ DATA1_XPATH_INDEXING_ENABLE
Definition: data1.h:349
#define D1_MAPTAG_numeric
Definition: data1.h:89
#define DATA1T_numeric
Definition: data1.h:204
data1_mapunit * map
Definition: data1.h:107
char * target_absyn_name
Definition: data1.h:106
Odr_oid * oid
Definition: data1.h:105
char * name
Definition: data1.h:104
struct data1_maptab * next
Definition: data1.h:108
int new_field
Definition: data1.h:87
struct data1_maptag * next
Definition: data1.h:97
union data1_maptag::@0 value
int type
Definition: data1.h:88
int which
Definition: data1.h:91
char * string
Definition: data1.h:95
int numeric
Definition: data1.h:94
struct data1_mapunit * next
Definition: d1_map.c:40
int no_chop
Definition: d1_map.c:37
data1_maptag * target_path
Definition: d1_map.c:39
int no_data
Definition: d1_map.c:36
char * source_element_name
Definition: d1_map.c:38
char * name
Definition: data1.h:114
struct data1_node::@2::@3 root
struct data1_node * child
Definition: data1.h:341
char * tag
Definition: data1.h:296
struct data1_node * next
Definition: data1.h:340
struct data1_node * last_child
Definition: data1.h:342
union data1_node::@2 u
int which
Definition: data1.h:285
data1_name * names
Definition: data1.h:203