QOF  0.7.5
qsf-xml-map.c
1 /***************************************************************************
2  * qsf-xml-map.c
3  *
4  * Sat Jan 1 07:31:55 2005
5  * Copyright 2005-2006 Neil Williams
6  * linux@codehelp.co.uk
7  ****************************************************************************/
8 /*
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22  */
23 
24 #include "config.h"
25 #include <glib.h>
26 #include <libxml/xmlversion.h>
27 #include <libxml/xmlmemory.h>
28 #include <libxml/tree.h>
29 #include <libxml/parser.h>
30 #include <libxml/xmlschemas.h>
31 #include "qof.h"
32 #include "qof-backend-qsf.h"
33 #include "qsf-xml.h"
34 #include "qsf-dir.h"
35 
36 static QofLogModule log_module = QOF_MOD_QSF;
37 
38 static void
39 qsf_date_default_handler (const gchar * default_name,
40  GHashTable * qsf_default_hash,
41  xmlNodePtr parent_tag, xmlNodePtr import_node, xmlNsPtr ns)
42 {
43  xmlNodePtr output_parent;
44  time_t *qsf_time;
45  gchar date_as_string[QSF_DATE_LENGTH];
46 
47  output_parent = xmlAddChild (parent_tag, xmlNewNode (ns,
48  xmlGetProp (import_node, BAD_CAST QSF_OBJECT_TYPE)));
49  xmlNewProp (output_parent, BAD_CAST QSF_OBJECT_TYPE,
50  xmlGetProp (import_node, BAD_CAST MAP_VALUE_ATTR));
51  qsf_time =
52  (time_t *) g_hash_table_lookup (qsf_default_hash, default_name);
53  strftime (date_as_string, QSF_DATE_LENGTH, QSF_XSD_TIME,
54  gmtime (qsf_time));
55  xmlNodeAddContent (output_parent, BAD_CAST date_as_string);
56 }
57 
58 static void
59 qsf_string_default_handler (const gchar * default_name,
60  GHashTable * qsf_default_hash,
61  xmlNodePtr parent_tag, xmlNodePtr import_node, xmlNsPtr ns)
62 {
63  xmlNodePtr node;
64  xmlChar *output;
65 
66  node = xmlAddChild (parent_tag,
67  xmlNewNode (ns,
68  xmlGetProp (import_node, BAD_CAST QSF_OBJECT_TYPE)));
69  xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE,
70  xmlGetProp (import_node, BAD_CAST MAP_VALUE_ATTR));
71  output =
72  (xmlChar *) g_hash_table_lookup (qsf_default_hash, default_name);
73  xmlNodeAddContent (node, output);
74 }
75 
76 static void
77 qsf_map_validation_handler (xmlNodePtr child, xmlNsPtr ns,
78  QsfValidator * valid)
79 {
80  xmlChar *qof_version, *obj_type;
81  gboolean match, is_registered;
82  gchar *buff;
83  xmlNodePtr child_node;
84  QsfStatus type, incoming_type;
85 
86  match = FALSE;
87  buff = NULL;
88  is_registered = FALSE;
89  type = QSF_NO_OBJECT;
90  if (qsf_is_element (child, ns, MAP_DEFINITION_TAG))
91  {
92  qof_version = xmlGetProp (child, BAD_CAST MAP_QOF_VERSION);
93  buff = g_strdup_printf ("%i", QSF_QOF_VERSION);
94  if (xmlStrcmp (qof_version, BAD_CAST buff) != 0)
95  {
96  PERR (" Wrong QOF_VERSION in map '%s', should be %s",
97  qof_version, buff);
98  valid->error_state = QOF_FATAL;
99  g_free (buff);
100  return;
101  }
102  g_free (buff);
103  for (child_node = child->children; child_node != NULL;
104  child_node = child_node->next)
105  {
106  if (qsf_is_element (child_node, ns, MAP_DEFINE_TAG))
107  {
108  obj_type = xmlGetProp (child_node, MAP_E_TYPE);
109  type = QSF_DEFINED_OBJECT;
110  is_registered = qof_class_is_registered (obj_type);
111  if (is_registered)
112  {
113  type = QSF_REGISTERED_OBJECT;
114  }
115  g_hash_table_insert (valid->map_table, obj_type,
116  GINT_TO_POINTER (type));
117  }
118  }
119  }
120  if (qsf_is_element (child, ns, MAP_OBJECT_TAG))
121  {
122  obj_type = xmlGetProp (child, BAD_CAST MAP_TYPE_ATTR);
123  /* check each listed object is either registered or calculated. */
124  type =
125  GPOINTER_TO_INT (g_hash_table_lookup
126  (valid->map_table, obj_type));
127  switch (type)
128  {
129  case QSF_DEFINED_OBJECT:
130  /* we have a calculation for an unregistered object. */
131  /* Ignore the calculation that exists to support bidirectional maps. */
132  /* Check that the incoming QSF contains data for this object */
133  {
134  /* lookup the same object in QSF object_table */
135  incoming_type =
136  GPOINTER_TO_INT (g_hash_table_lookup
137  (valid->object_table, obj_type));
138  switch (incoming_type)
139  {
140  case QSF_DEFINED_OBJECT:
141  {
142  valid->incoming_count++;
143  g_hash_table_insert (valid->map_table, obj_type,
144  GINT_TO_POINTER (type));
145  break; /* good, proceed. */
146  }
147  default:
148  {
149  PERR (" Missing data: %s", obj_type);
150  type = QSF_INVALID_OBJECT;
151  break;
152  }
153  }
154  break;
155  }
156  case QSF_REGISTERED_OBJECT: /* use this calculation. */
157  {
158  type = QSF_CALCULATED_OBJECT;
159  valid->map_calculated_count++;
160  valid->qof_registered_count++;
161  /* store the result */
162  g_hash_table_insert (valid->map_table, obj_type,
163  GINT_TO_POINTER (type));
164  break;
165  }
166  default:
167  {
168  type = QSF_INVALID_OBJECT;
169  break;
170  }
171  }
172  PINFO (" final type=%s result=%d", obj_type, type);
173  if (type == QSF_INVALID_OBJECT)
174  {
175  valid->error_state = QOF_FATAL;
176  }
177  }
178 }
179 
180 static QofErrorId
181 check_qsf_object_with_map_internal (xmlDocPtr map_doc, xmlDocPtr doc)
182 {
183  xmlNodePtr map_root, object_root;
184  struct QsfNodeIterate qsfiter;
185  QsfValidator valid;
186  xmlNsPtr map_ns;
187 
188  valid.map_table = g_hash_table_new (g_str_hash, g_str_equal);
189  valid.object_table = g_hash_table_new (g_str_hash, g_str_equal);
190  map_root = xmlDocGetRootElement (map_doc);
191  object_root = xmlDocGetRootElement (doc);
192  valid.map_calculated_count = 0;
193  valid.valid_object_count = 0;
194  valid.qof_registered_count = 0;
195  valid.incoming_count = 0;
196  valid.error_state = QOF_SUCCESS;
197  map_ns = map_root->ns;
198  qsfiter.ns = object_root->ns;
199  qsf_valid_foreach (object_root, qsf_object_validation_handler,
200  &qsfiter, &valid);
201  qsfiter.ns = map_ns;
202  qsf_valid_foreach (map_root, qsf_map_validation_handler, &qsfiter,
203  &valid);
204  if (valid.error_state != QOF_SUCCESS)
205  {
206  PINFO (" Map is wrong. Trying the next map.");
207  g_hash_table_destroy (valid.object_table);
208  g_hash_table_destroy (valid.map_table);
209  return valid.error_state;
210  }
211  /* check all counted objects are valid:
212  Objects to be calculated must also be registered
213  so that new objects can be created and populated
214  from the incoming data: qof_registered_count > 0
215  The incoming data must contain valid objects -
216  not an empty QofBook: valid_object_count > 0
217  The map must contain at least some calculations:
218  map_calculated_count > 0
219  */
220  if ((valid.qof_registered_count < 1)
221  || (valid.map_calculated_count < 1)
222  || (valid.valid_object_count < 1)
223  || (valid.incoming_count < g_hash_table_size (valid.object_table)))
224  {
225  PINFO
226  (" Map is wrong. map:%d object:%d reg:%d incoming:%d size:%d",
227  valid.map_calculated_count, valid.valid_object_count,
228  valid.qof_registered_count, valid.incoming_count,
229  g_hash_table_size (valid.object_table));
230  g_hash_table_destroy (valid.object_table);
231  g_hash_table_destroy (valid.map_table);
232  return valid.error_state;
233  }
234  g_hash_table_destroy (valid.object_table);
235  g_hash_table_destroy (valid.map_table);
236  return QOF_SUCCESS;
237 }
238 
239 gboolean
240 is_qsf_object_with_map_be (gchar * map_file, QsfParam * params)
241 {
242  xmlDocPtr doc, map_doc;
243  QofErrorId result;
244  gchar *path, *map_path;
245 
246  g_return_val_if_fail ((params != NULL), FALSE);
247  path = g_strdup (params->filepath);
248  map_path = g_strdup_printf ("%s/%s", QSF_SCHEMA_DIR, map_file);
249  PINFO (" checking map file '%s'", map_path);
250  if (path == NULL)
251  {
252  qof_error_set_be (params->be, qof_error_register
253  (_("The QSF XML file '%s' could not be found."), TRUE));
254  return FALSE;
255  }
256  doc = xmlParseFile (path);
257  if (doc == NULL)
258  {
259  qof_error_set_be (params->be, qof_error_register
260  (_("There was an error parsing the file '%s'."), TRUE));
261  return FALSE;
262  }
263  if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
264  {
265  qof_error_set_be (params->be, qof_error_register
266  (_("Invalid QSF Object file! The QSF object file '%s' "
267  " failed to validate against the QSF object schema. "
268  "The XML structure of the file is either not well-formed "
269  "or the file contains illegal data."), TRUE));
270  return FALSE;
271  }
272  if (map_path == NULL)
273  {
274  qof_error_set_be (params->be, qof_error_register
275  (_("The QSF map file '%s' could not be found."), TRUE));
276  return FALSE;
277  }
278  map_doc = xmlParseFile (map_path);
279  if (map_doc == NULL)
280  {
281  qof_error_set_be (params->be, qof_error_register
282  (_("There was an error parsing the file '%s'."), TRUE));
283  return FALSE;
284  }
285  result = check_qsf_object_with_map_internal (map_doc, doc);
286  return (result == QOF_SUCCESS) ? TRUE : FALSE;
287 }
288 
289 gboolean
290 is_qsf_object_with_map (const gchar * path, gchar * map_file)
291 {
292  xmlDocPtr doc, map_doc;
293  QofErrorId result;
294  gchar *map_path;
295 
296  map_path = g_strdup_printf ("%s/%s", QSF_SCHEMA_DIR, map_file);
297  if (path == NULL)
298  {
299  return FALSE;
300  }
301  doc = xmlParseFile (path);
302  if (doc == NULL)
303  {
304  return FALSE;
305  }
306  if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
307  {
308  return FALSE;
309  }
310  if (map_path == NULL)
311  {
312  return FALSE;
313  }
314  map_doc = xmlParseFile (map_path);
315  result = check_qsf_object_with_map_internal (map_doc, doc);
316  return (result == QOF_SUCCESS) ? TRUE : FALSE;
317 }
318 
319 gboolean
320 is_qsf_map_be (QsfParam * params)
321 {
322  xmlDocPtr doc;
323  struct QsfNodeIterate qsfiter;
324  QsfValidator valid;
325  xmlNodePtr map_root;
326  xmlNsPtr map_ns;
327  gchar *path;
328 
329  g_return_val_if_fail ((params != NULL), FALSE);
330  path = g_strdup (params->filepath);
331  if (path == NULL)
332  {
333  qof_error_set_be (params->be, qof_error_register
334  (_("The QSF XML file '%s' could not be found."), TRUE));
335  return FALSE;
336  }
337  doc = xmlParseFile (path);
338  if (doc == NULL)
339  {
340  qof_error_set_be (params->be, qof_error_register
341  (_("There was an error parsing the file '%s'."), TRUE));
342  return FALSE;
343  }
344  if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_MAP_SCHEMA, doc))
345  {
346  qof_error_set_be (params->be,
348  _("Invalid QSF Map file! The QSF map file "
349  "failed to validate against the QSF map schema. "
350  "The XML structure of the file is either not well-formed "
351  "or the file contains illegal data."), FALSE));
352  return FALSE;
353  }
354  map_root = xmlDocGetRootElement (doc);
355  map_ns = map_root->ns;
356  qsfiter.ns = map_ns;
357  valid.object_table = g_hash_table_new (g_str_hash, g_str_equal);
358  valid.map_table = g_hash_table_new (g_str_hash, g_str_equal);
359  valid.error_state = QOF_SUCCESS;
360  qsf_valid_foreach (map_root, qsf_map_validation_handler,
361  &qsfiter, &valid);
362  if (valid.error_state != QOF_SUCCESS)
363  {
364  g_hash_table_destroy (valid.object_table);
365  return FALSE;
366  }
367  g_hash_table_destroy (valid.object_table);
368  return TRUE;
369 }
370 
371 gboolean
372 is_qsf_map (const gchar * path)
373 {
374  xmlDocPtr doc;
375  struct QsfNodeIterate qsfiter;
376  QsfValidator valid;
377  xmlNodePtr map_root;
378  xmlNsPtr map_ns;
379 
380  g_return_val_if_fail ((path != NULL), FALSE);
381  if (path == NULL)
382  {
383  return FALSE;
384  }
385  doc = xmlParseFile (path);
386  if (doc == NULL)
387  {
388  return FALSE;
389  }
390  if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_MAP_SCHEMA, doc))
391  {
392  return FALSE;
393  }
394  map_root = xmlDocGetRootElement (doc);
395  map_ns = map_root->ns;
396  qsfiter.ns = map_ns;
397  valid.error_state = QOF_SUCCESS;
398  valid.map_table = g_hash_table_new (g_str_hash, g_str_equal);
399  qsf_valid_foreach (map_root, qsf_map_validation_handler,
400  &qsfiter, &valid);
401  if (valid.error_state != QOF_SUCCESS)
402  {
403  g_hash_table_destroy (valid.map_table);
404  return FALSE;
405  }
406  g_hash_table_destroy (valid.map_table);
407  return TRUE;
408 }
409 
410 static void
411 qsf_map_default_handler (xmlNodePtr child, xmlNsPtr ns, QsfParam * params)
412 {
413  xmlChar *qsf_enum;
414  gchar *iterate;
415  QofErrorId bad_map;
416 
417  g_return_if_fail (params->qsf_define_hash != NULL);
418  iterate = NULL;
419  bad_map = qof_error_register
420  (_("The selected QSF map '%s' contains unusable or "
421  "missing data. This is usually because not all the "
422  "required parameters for the defined objects have "
423  "calculations described in the map."), TRUE);
424  if (qsf_is_element (child, ns, MAP_DEFINE_TAG))
425  {
426  iterate = xmlGetProp (child, MAP_ITERATE_ATTR);
427  if ((qof_util_bool_to_int (iterate) == 1) &&
429  (xmlGetProp (child, BAD_CAST MAP_E_TYPE))))
430  {
431  params->qof_foreach = xmlGetProp (child, BAD_CAST MAP_E_TYPE);
432  PINFO (" iterating over '%s' objects", params->qof_foreach);
433  }
434  if (NULL == g_hash_table_lookup (params->qsf_define_hash,
435  xmlGetProp (child, BAD_CAST MAP_E_TYPE)))
436  {
437  g_hash_table_insert (params->qsf_define_hash,
438  xmlGetProp (child, BAD_CAST MAP_E_TYPE),
439  params->child_node);
440  }
441  else
442  {
443  qof_error_set_be (params->be, bad_map);
444  PERR (" ERR_QSF_BAD_MAP set");
445  return;
446  }
447  }
448  if (qsf_is_element (child, ns, MAP_DEFAULT_TAG))
449  {
450  if (qsf_strings_equal
451  (xmlGetProp (child, BAD_CAST MAP_TYPE_ATTR), MAP_ENUM_TYPE))
452  {
453  qsf_enum = xmlNodeGetContent (child);
455  PERR (" enum todo incomplete");
459  if (NULL == g_hash_table_lookup (params->qsf_default_hash,
460  xmlNodeGetContent (child)))
461  {
462  g_hash_table_insert (params->qsf_default_hash,
463  xmlNodeGetContent (child), child);
464  }
465  else
466  {
467  qof_error_set_be (params->be, bad_map);
468  PERR (" ERR_QSF_BAD_MAP set");
469  return;
470  }
471  }
473  else
474  {
475  if (NULL == g_hash_table_lookup (params->qsf_default_hash,
476  xmlGetProp (child, BAD_CAST MAP_NAME_ATTR)))
477  {
478  g_hash_table_insert (params->qsf_default_hash,
479  xmlGetProp (child, BAD_CAST MAP_NAME_ATTR), child);
480  }
481  else
482 /* if(0 != xmlHashAddEntry(params->default_map,
483  xmlGetProp(child_node, MAP_NAME_ATTR), child_node))*/
484  {
485  qof_error_set_be (params->be, bad_map);
486  PERR (" ERR_QSF_BAD_MAP set");
487  return;
488  }
489  }
490  }
491 }
492 
493 static void
494 qsf_map_top_node_handler (xmlNodePtr child, xmlNsPtr ns,
495  QsfParam * params)
496 {
497  xmlChar *qof_version;
498  gchar *buff;
499  struct QsfNodeIterate qsfiter;
500 
501  if (!params->qsf_define_hash)
502  return;
503  if (!params->qsf_default_hash)
504  return;
505  ENTER (" map top node child=%s", child->name);
506  buff = NULL;
507  if (qsf_is_element (child, ns, MAP_DEFINITION_TAG))
508  {
509  qof_version = xmlGetProp (child, BAD_CAST MAP_QOF_VERSION);
510  buff = g_strdup_printf ("%i", QSF_QOF_VERSION);
511  if (xmlStrcmp (qof_version, BAD_CAST buff) != 0)
512  {
513  qof_error_set_be (params->be, qof_error_register(
514  _("The QSF Map file '%s' was written for a different "
515  "version of QOF. It may need to be modified to work with "
516  "your current QOF installation."), TRUE));
517  LEAVE (" BAD QOF VERSION");
518  return;
519  }
520  qsfiter.ns = ns;
521  qsf_node_foreach (child, qsf_map_default_handler, &qsfiter, params);
522  }
523  LEAVE (" ");
524 }
525 
526 static char *
527 qsf_else_set_value (xmlNodePtr parent, gchar * content,
528  xmlNsPtr map_ns)
529 {
530  xmlNodePtr cur_node;
531 
532  content = NULL;
533  for (cur_node = parent->children; cur_node != NULL;
534  cur_node = cur_node->next)
535  {
536  if (qsf_is_element (cur_node, map_ns, QSF_CONDITIONAL_SET))
537  {
538  content = (gchar *) xmlNodeGetContent (cur_node);
539  return content;
540  }
541  }
542  return NULL;
543 }
544 
545 /* Handles the set tag in the map.
546 This function will be overhauled once inside QOF
547 QOF hook required for "Lookup in the receiving application"
548 */
549 static gchar *
550 qsf_set_handler (xmlNodePtr parent, GHashTable * default_hash,
551  gchar * content, QsfParam * params)
552 {
553  xmlNodePtr cur_node, lookup_node;
554 
555  ENTER (" lookup problem");
556  content = NULL;
557  for (cur_node = parent->children; cur_node != NULL;
558  cur_node = cur_node->next)
559  {
560  if (qsf_is_element (cur_node, params->map_ns, QSF_CONDITIONAL_SET))
561  {
562  content = (gchar *) xmlGetProp (cur_node, BAD_CAST QSF_OPTION);
563  if (qsf_strings_equal (xmlGetProp (cur_node,
564  BAD_CAST QSF_OPTION), "qsf_lookup_string"))
565  {
566  lookup_node =
567  (xmlNodePtr) g_hash_table_lookup (default_hash,
568  xmlNodeGetContent (cur_node));
569  content =
570  (gchar *) xmlGetProp (lookup_node,
571  BAD_CAST MAP_VALUE_ATTR);
573  /* Find by name, get GUID, return GUID as string. */
574  g_message ("Lookup %s in the receiving application\n",
575  content);
576  LEAVE (" todo");
577  return content;
578  }
579  if (content)
580  {
581  lookup_node =
582  (xmlNodePtr) g_hash_table_lookup (default_hash,
583  xmlNodeGetContent (cur_node));
584  content =
585  (gchar *) xmlGetProp (lookup_node, BAD_CAST "value");
586  return content;
587  }
588  content = (gchar *) xmlGetProp (parent, BAD_CAST "boolean");
589  if (!content)
590  {
592  lookup_node =
593  (xmlNodePtr) g_hash_table_lookup (params->
594  qsf_parameter_hash,
595  xmlGetProp (parent->parent, BAD_CAST MAP_TYPE_ATTR));
596  if (lookup_node)
597  {
598  return (gchar *) xmlNodeGetContent (lookup_node);
599  }
600  LEAVE (" check arguments");
601  return (gchar *) xmlNodeGetContent (cur_node);
602  }
603  }
604  }
605  LEAVE (" null");
606  return NULL;
607 }
608 
609 static void
610 qsf_calculate_else (xmlNodePtr param_node, xmlNodePtr child,
611  QsfParam * params)
612 {
613  xmlNodePtr export_node;
614  xmlChar *output_content, *object_data;
615 
616  if (qsf_is_element (param_node, params->map_ns, QSF_CONDITIONAL_ELSE))
617  {
618  if (params->boolean_calculation_done == 0)
619  {
620  output_content = object_data = NULL;
621  output_content = BAD_CAST qsf_set_handler (param_node,
622  params->
623  qsf_default_hash, (gchar *) output_content, params);
624  if (output_content == NULL)
625  {
626  output_content =
627  xmlGetProp (param_node, BAD_CAST MAP_TYPE_ATTR);
628  object_data =
629  BAD_CAST qsf_else_set_value (param_node,
630  (gchar *) output_content, params->map_ns);
631  output_content =
632  BAD_CAST xmlGetProp ((xmlNodePtr)
633  g_hash_table_lookup (params->
634  qsf_default_hash,
635  object_data), BAD_CAST MAP_VALUE_ATTR);
636  }
637  if (object_data != NULL)
638  {
639  export_node =
640  (xmlNodePtr) g_hash_table_lookup (params->
641  qsf_parameter_hash,
642  xmlGetProp (params->
643  child_node, BAD_CAST QSF_OBJECT_TYPE));
644  object_data = xmlNodeGetContent (export_node);
645  }
646  if (output_content != NULL)
647  {
648  object_data = output_content;
649  }
650  export_node =
651  xmlAddChild (params->lister,
652  xmlNewNode (params->qsf_ns,
653  xmlGetProp (child, BAD_CAST QSF_OBJECT_TYPE)));
654  xmlNewProp (export_node, BAD_CAST QSF_OBJECT_TYPE,
655  xmlGetProp (child, BAD_CAST MAP_VALUE_ATTR));
656  xmlNodeAddContent (export_node, object_data);
657  params->boolean_calculation_done = 1;
658  }
659  }
660 }
661 
662 static void
663 qsf_set_format_value (xmlChar * format, gchar * qsf_time_now_as_string,
664  xmlNodePtr cur_node, QsfParam * params)
665 {
666  gint result;
667  xmlChar *content;
668  time_t *output;
669  struct tm *tmp;
670  time_t tester;
671  xmlNodePtr kl;
672  regex_t reg;
673 
676  result = 0;
677  if (format == NULL)
678  {
679  return;
680  }
681  ENTER (" ");
682  content = xmlNodeGetContent (cur_node);
683  output =
684  (time_t *) g_hash_table_lookup (params->qsf_default_hash, content);
685  if (!output)
686  {
689  tester = time (NULL);
690  tmp = gmtime (&tester);
693  kl = (xmlNodePtr) g_hash_table_lookup (params->qsf_parameter_hash,
694  content);
695  if (!kl)
696  {
697  LEAVE (" no suitable date set.");
698  return;
699  }
701  strptime ((char *) xmlNodeGetContent (kl), QSF_XSD_TIME, tmp);
702  if (!tmp)
703  {
704  LEAVE (" empty date field in QSF object.\n");
705  return;
706  }
707  tester = mktime (tmp);
708  output = &tester;
709  }
710  result = regcomp (&reg, "%[a-zA-Z]", REG_EXTENDED | REG_NOSUB);
711  result = regexec (&reg, (gchar *) format, (size_t) 0, NULL, 0);
712  if (result == REG_NOMATCH)
713  {
714  format = BAD_CAST "%F";
715  }
716  regfree (&reg);
717  /* QSF_DATE_LENGTH preset for all internal and QSF_XSD_TIME string formats. */
718  strftime (qsf_time_now_as_string, QSF_DATE_LENGTH, (char *) format,
719  gmtime (output));
720  LEAVE (" ok");
721 }
722 
723 static void
724 qsf_boolean_set_value (xmlNodePtr parent, QsfParam * params,
725  gchar * content, xmlNsPtr map_ns)
726 {
727  xmlNodePtr cur_node;
728  xmlChar *boolean_name;
729 
730  boolean_name = NULL;
731  for (cur_node = parent->children; cur_node != NULL;
732  cur_node = cur_node->next)
733  {
734  if (qsf_is_element (cur_node, map_ns, QSF_CONDITIONAL_SET))
735  {
736  boolean_name =
737  xmlGetProp (cur_node, BAD_CAST QSF_FORMATTING_OPTION);
738  qsf_set_format_value (boolean_name, content, cur_node, params);
739  }
740  }
741 }
742 
743 static void
744 qsf_calculate_conditional (xmlNodePtr param_node, xmlNodePtr child,
745  QsfParam * params)
746 {
747  xmlNodePtr export_node;
748  xmlChar *output_content;
749 
750  output_content = NULL;
751  if (qsf_is_element (param_node, params->map_ns, QSF_CONDITIONAL))
752  {
753  if (params->boolean_calculation_done == 0)
754  {
755  /* set handler */
756  output_content =
757  BAD_CAST qsf_set_handler (param_node,
758  params->qsf_default_hash,
759  (gchar *) output_content, params);
760  /* If the 'if' contains a boolean that has a default value */
761  if (output_content == NULL)
762  {
763  if (NULL !=
764  xmlGetProp (param_node, BAD_CAST QSF_BOOLEAN_DEFAULT))
765  {
766  output_content =
767  xmlGetProp ((xmlNodePtr)
768  g_hash_table_lookup (params->
769  qsf_default_hash,
770  xmlGetProp
771  (param_node,
772  BAD_CAST
773  QSF_BOOLEAN_DEFAULT)),
774  BAD_CAST MAP_VALUE_ATTR);
775  }
776  /* Is the default set to true? */
777  if (0 ==
778  qsf_compare_tag_strings (output_content,
780  {
781  qsf_boolean_set_value (param_node, params,
782  (gchar *) output_content, params->map_ns);
783  export_node =
784  xmlAddChild (params->lister,
785  xmlNewNode (params->qsf_ns,
786  xmlGetProp (child, BAD_CAST QSF_OBJECT_TYPE)));
787  xmlNewProp (export_node, BAD_CAST QSF_OBJECT_TYPE,
788  xmlGetProp (child, BAD_CAST MAP_VALUE_ATTR));
789  xmlNodeAddContent (export_node, output_content);
790  params->boolean_calculation_done = 1;
791  }
792  }
793  }
794  }
795 }
796 
797 static void
798 qsf_add_object_tag (QsfParam * params, gint count)
799 {
800  xmlNodePtr extra_node;
801  GString *str;
802  xmlChar *property;
803 
804  str = g_string_new (" ");
805  g_string_printf (str, "%i", count);
806  extra_node = NULL;
807  extra_node = xmlAddChild (params->output_node,
808  xmlNewNode (params->qsf_ns, BAD_CAST QSF_OBJECT_TAG));
809  xmlNewProp (extra_node, BAD_CAST QSF_OBJECT_TYPE,
810  xmlGetProp (params->convert_node, BAD_CAST QSF_OBJECT_TYPE));
811  property = xmlCharStrdup (str->str);
812  xmlNewProp (extra_node, BAD_CAST QSF_OBJECT_COUNT, property);
813  params->lister = extra_node;
814 }
815 
816 static gint
817 identify_source_func (gconstpointer qsf_object, gconstpointer map)
818 {
819  PINFO (" qsf_object=%s, map=%s",
820  ((QsfObject *) qsf_object)->object_type, (QofIdType) map);
821  return safe_strcmp (((QsfObject *) qsf_object)->object_type,
822  (QofIdType) map);
823 }
824 
825 static void
826 qsf_map_calculate_output (xmlNodePtr param_node, xmlNodePtr child,
827  QsfParam * params)
828 {
829  xmlNodePtr export_node;
830  xmlChar *output_content;
831  xmlNodePtr input_node;
832  GList *source;
833 
834  output_content = xmlNodeGetContent (param_node);
835  DEBUG (" %s", output_content);
836  /* source refers to the source object that provides the data */
837  source = g_list_find_custom (params->qsf_object_list,
838  BAD_CAST xmlGetProp (param_node,
839  MAP_OBJECT_ATTR), identify_source_func);
840  PINFO (" checking %s", BAD_CAST xmlGetProp (param_node,
841  MAP_OBJECT_ATTR));
842  if (!source)
843  {
844  DEBUG (" no source found in list.");
845  return;
846  }
847  params->object_set = source->data;
848  input_node = g_hash_table_lookup (params->object_set->parameters,
849  output_content);
850  DEBUG (" node_value=%s, content=%s",
851  xmlGetProp (child, BAD_CAST MAP_VALUE_ATTR),
852  xmlNodeGetContent (input_node));
853  export_node = xmlAddChild (params->lister, xmlNewNode (params->qsf_ns,
854  xmlGetProp (child, BAD_CAST QSF_OBJECT_TYPE)));
855  xmlNewProp (export_node, BAD_CAST QSF_OBJECT_TYPE,
856  xmlGetProp (child, BAD_CAST MAP_VALUE_ATTR));
857  xmlNodeAddContent (export_node, xmlNodeGetContent (input_node));
858 }
859 
860 static void
861 qsf_map_object_handler (xmlNodePtr child, xmlNsPtr ns, QsfParam * params)
862 {
863  xmlNodePtr param_node;
864  xmlNsPtr map_ns, qsf_ns;
865  gint result;
866 
867  map_ns = ns;
868  qsf_ns = params->qsf_ns;
869  param_node = NULL;
870  result = 0;
871  if (child == NULL)
872  {
873  return;
874  }
875  if (ns == NULL)
876  {
877  return;
878  }
879  params->boolean_calculation_done = 0;
880 
881  if (qsf_is_element (child, map_ns, MAP_CALCULATE_TAG))
882  {
883  params->boolean_calculation_done = 0;
884  /* read the child nodes to prepare the calculation. */
885  for (param_node = child->children; param_node != NULL;
886  param_node = param_node->next)
887  {
888  if (qsf_is_element (param_node, map_ns, QSF_CONDITIONAL_SET))
889  {
890  /* Map the pre-defined defaults */
891  if (0 ==
892  qsf_compare_tag_strings (xmlNodeGetContent
893  (param_node), "qsf_enquiry_date"))
894  {
895  qsf_string_default_handler ("qsf_enquiry_date",
896  params->qsf_default_hash,
897  params->lister, child, qsf_ns);
898  }
899  if (0 ==
900  qsf_compare_tag_strings (xmlNodeGetContent
901  (param_node), "qsf_time_now"))
902  {
903  qsf_date_default_handler ("qsf_time_now",
904  params->qsf_default_hash,
905  params->lister, child, qsf_ns);
906  }
907  if (0 ==
908  qsf_compare_tag_strings (xmlNodeGetContent
909  (param_node), "qsf_time_string"))
910  {
911  qsf_string_default_handler ("qsf_time_string",
912  params->qsf_default_hash,
913  params->lister, child, qsf_ns);
914  }
915  qsf_map_calculate_output (param_node, child, params);
916  }
917  qsf_calculate_conditional (param_node, child, params);
918  qsf_calculate_else (param_node, child, params);
919  }
920  /* calculate_map currently not in use */
921  /* ensure uniqueness of the key before re-instating */
922 /* result = xmlHashAddEntry2(calculate_map,
923  xmlGetProp(child_node, MAP_TYPE_ATTR),
924  xmlGetProp(child_node, MAP_VALUE_ATTR), child_node);
925  if(result != 0) {
926  printf("add entry to calculate hash failed. %s\t%s\t%s.\n",
927  xmlGetProp(child_node, MAP_TYPE_ATTR),
928  xmlGetProp(child_node, MAP_VALUE_ATTR), child_node->name);
929  return;
930  }
931 
932  is_qsf_object_with_map(path, map_path);
933 */
934  }
935 }
936 
937 static void
938 iterator_cb (xmlNodePtr child, xmlNsPtr ns, QsfParam * params)
939 {
940  gchar *object_name;
941 
942  /* count the number of iterators in the QSF file */
943  if (qsf_is_element (child, ns, QSF_OBJECT_TAG))
944  {
945  object_name = xmlGetProp (child, QSF_OBJECT_TYPE);
946  if (0 == safe_strcmp (object_name, params->qof_foreach))
947  {
948  params->foreach_limit++;
949  }
950  }
951 }
952 
953 xmlDocPtr
954 qsf_object_convert (xmlDocPtr mapDoc, xmlNodePtr qsf_root,
955  QsfParam * params)
956 {
957  /* mapDoc : map document. qsf_root: incoming QSF root node. */
958  struct QsfNodeIterate qsfiter;
959  xmlDocPtr output_doc;
960  xmlNode *cur_node;
961  xmlNode *map_root, *output_root;
962 
963  g_return_val_if_fail ((mapDoc && qsf_root && params), NULL);
964  ENTER (" root=%s", qsf_root->name);
965  /* prepare the intermediary document */
966  qsfiter.ns = params->qsf_ns;
967  output_doc = xmlNewDoc (BAD_CAST QSF_XML_VERSION);
968  output_root = xmlNewNode (NULL, BAD_CAST QSF_ROOT_TAG);
969  xmlDocSetRootElement (output_doc, output_root);
970  xmlSetNs (output_root, params->qsf_ns);
971  params->output_node = xmlNewChild (output_root, params->qsf_ns,
972  BAD_CAST QSF_BOOK_TAG, NULL);
973  xmlNewProp (params->output_node, BAD_CAST QSF_BOOK_COUNT,
974  BAD_CAST "1");
975  /* parse the incoming QSF */
976  qsf_book_node_handler (qsf_root->children->next, params->qsf_ns,
977  params);
978  /* parse the map and calculate the values */
979  map_root = xmlDocGetRootElement (mapDoc);
980  params->foreach_limit = 0;
981  qsfiter.ns = params->map_ns;
982  /* sets qof_foreach iterator, defines and defaults. */
983  qsf_node_foreach (map_root, qsf_map_top_node_handler, &qsfiter, params);
984  /* identify the entities of iterator type. */
985  qsfiter.ns = params->qsf_ns;
986  qsf_node_foreach (qsf_root->children->next, iterator_cb, &qsfiter,
987  params);
988  PINFO (" counted %d records", params->foreach_limit);
989  params->count = 0;
990  for (cur_node = map_root->children; cur_node != NULL;
991  cur_node = cur_node->next)
992  {
993  params->convert_node = cur_node;
994  if (qsf_is_element (cur_node, params->map_ns, MAP_OBJECT_TAG))
995  {
996  gint i;
997 
998  params->lister = NULL;
999  PINFO (" found an object tag. starting calculation");
1000  /* cur_node describes the target object */
1001  if (!qof_class_is_registered (BAD_CAST
1002  xmlGetProp (cur_node, MAP_TYPE_ATTR)))
1003  {
1004  continue;
1005  }
1006  qsf_add_object_tag (params, params->count);
1007  params->count++;
1008  qsfiter.ns = params->map_ns;
1009  PINFO (" params->foreach_limit=%d", params->foreach_limit);
1010  for (i = -1; i < params->foreach_limit; i++)
1011  {
1012  qsf_node_foreach (cur_node, qsf_map_object_handler,
1013  &qsfiter, params);
1014  params->qsf_object_list =
1015  g_list_next (params->qsf_object_list);
1016  params->count++;
1017  }
1018  }
1019  }
1020  params->file_type = OUR_QSF_OBJ;
1021  /* use for debugging */
1022  xmlSaveFormatFileEnc ("-", output_doc, "UTF-8", 1);
1023  LEAVE (" ");
1024  return output_doc;
1025 }