QOF: qsf-xml-map.c Source File

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,
347 qof_error_register (
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) &&
428 (qof_class_is_registered
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,
779 QSF_XML_BOOLEAN_TEST))
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 }
QsfMetadata_s
QSF Parameters.
Definition: qsf-xml.h:469
QSF_NO_OBJECT
Definition: qsf-xml.h:449
QsfMetadata_s::qsf_ns
xmlNsPtr qsf_ns
Definition: qsf-xml.h:507
QsfValidates_s::map_calculated_count
gint map_calculated_count
Definition: qsf-xml.h:575
MAP_E_TYPE
#define MAP_E_TYPE
Definition: qsf-xml.h:303
MAP_ITERATE_ATTR
#define MAP_ITERATE_ATTR
Definition: qsf-xml.h:158
qof_error_register
QofErrorId qof_error_register(const gchar *err_message, gboolean use_file)
Generate and register a new error.
Definition: qoferror.c:91
PERR
#define PERR(format, args...)
Definition: qoflog.h:183
qsf_object_validation_handler
void qsf_object_validation_handler(xmlNodePtr child, xmlNsPtr ns, QsfValidator *valid)
Checks all incoming objects for QOF registration.
Definition: qsf-xml.c:134
QofIdType
const gchar * QofIdType
Definition: qofid.h:81
PINFO
#define PINFO(format, args...)
Definition: qoflog.h:199
QSF_REGISTERED_OBJECT
Definition: qsf-xml.h:456
qof_class_is_registered
gboolean qof_class_is_registered(QofIdTypeConst obj_name)
Definition: qofclass.c:132
QSF_OBJECT_COUNT
#define QSF_OBJECT_COUNT
Definition: qsf-xml.h:105
MAP_DEFINE_TAG
#define MAP_DEFINE_TAG
Definition: qsf-xml.h:154
QSF_ROOT_TAG
#define QSF_ROOT_TAG
Definition: qsf-xml.h:81
is_qsf_object_with_map
gboolean is_qsf_object_with_map(const gchar *path, gchar *map_file)
Validate a QSF file and a selected QSF map.
Definition: qsf-xml-map.c:290
QsfValidates_s
Validation metadata.
Definition: qsf-xml.h:558
QsfValidates_s::map_table
GHashTable * map_table
Definition: qsf-xml.h:568
QsfMetadata_s::count
gint count
Definition: qsf-xml.h:476
qsf_valid_foreach
void qsf_valid_foreach(xmlNodePtr parent, QsfValidCB cb, struct QsfNodeIterate *qsfiter, QsfValidator *valid)
Definition: qsf-xml.c:102
QsfMetadata_s::file_type
QsfType file_type
Definition: qsf-xml.h:472
qsf_is_valid
gboolean qsf_is_valid(const gchar *schema_dir, const gchar *schema_filename, xmlDocPtr doc)
Compares an xmlDoc in memory against the schema file.
Definition: qsf-xml.c:75
QofErrorId
gint32 QofErrorId
The ID of this error.
Definition: qofbackend.h:54
MAP_DEFINITION_TAG
#define MAP_DEFINITION_TAG
Definition: qsf-xml.h:147
MAP_VALUE_ATTR
#define MAP_VALUE_ATTR
Definition: qsf-xml.h:289
MAP_OBJECT_ATTR
#define MAP_OBJECT_ATTR
Definition: qsf-xml.h:293
QsfMetadata_s::boolean_calculation_done
gint boolean_calculation_done
Definition: qsf-xml.h:531
MAP_TYPE_ATTR
#define MAP_TYPE_ATTR
Definition: qsf-xml.h:279
QSF_DEFINED_OBJECT
Definition: qsf-xml.h:453
QsfMetadata_s::be
QofBackend * be
Definition: qsf-xml.h:519
QSF_OBJECT_TAG
#define QSF_OBJECT_TAG
Definition: qsf-xml.h:101
OUR_QSF_OBJ
Definition: qsf-xml.h:52
MAP_ENUM_TYPE
#define MAP_ENUM_TYPE
Definition: qsf-xml.h:307
qsf-xml.h
Private QSF header - not for use by applications.
qof_util_bool_to_int
gint qof_util_bool_to_int(const gchar *val)
Definition: qofutil.c:249
QsfMetadata_s::foreach_limit
gint foreach_limit
Definition: qsf-xml.h:515
qsf_strings_equal
gint qsf_strings_equal(const xmlChar *node_name, gchar *tag_name)
shorthand function
Definition: qsf-xml.c:45
QSF_BOOK_COUNT
#define QSF_BOOK_COUNT
Definition: qsf-xml.h:99
LEAVE
#define LEAVE(format, args...)
Definition: qoflog.h:227
QSF_OBJECT_TYPE
#define QSF_OBJECT_TYPE
Definition: qsf-xml.h:103
qsf_compare_tag_strings
gint qsf_compare_tag_strings(const xmlChar *node_name, gchar *tag_name)
shorthand function
Definition: qsf-xml.c:39
QSF_CONDITIONAL_SET
#define QSF_CONDITIONAL_SET
Definition: qsf-xml.h:334
MAP_QOF_VERSION
#define MAP_QOF_VERSION
Definition: qsf-xml.h:260
QsfNodeIterate
One iterator, two typedefs.
Definition: qsf-xml.h:689
QsfMetadata_s::qof_foreach
QofIdType qof_foreach
Definition: qsf-xml.h:513
QSF_FORMATTING_OPTION
#define QSF_FORMATTING_OPTION
Definition: qsf-xml.h:376
QSF_BOOK_TAG
#define QSF_BOOK_TAG
Definition: qsf-xml.h:94
QSF_XML_BOOLEAN_TEST
#define QSF_XML_BOOLEAN_TEST
Definition: qsf-xml.h:417
MAP_DEFAULT_TAG
#define MAP_DEFAULT_TAG
Definition: qsf-xml.h:229
QsfMetadata_s::qsf_object_list
GList * qsf_object_list
Definition: qsf-xml.h:478
QSF_BOOLEAN_DEFAULT
#define QSF_BOOLEAN_DEFAULT
A specific boolean default for this map.
Definition: qsf-xml.h:310
QsfValidates_s::qof_registered_count
gint qof_registered_count
Definition: qsf-xml.h:578
QsfMetadata_s::convert_node
xmlNodePtr convert_node
Definition: qsf-xml.h:495
QsfStatus
QsfStatus
Status of various object during mapping.
Definition: qsf-xml.h:446
QOF_SUCCESS
#define QOF_SUCCESS
Definition: qoferror.h:124
qsf_node_foreach
void qsf_node_foreach(xmlNodePtr parent, QsfNodeCB cb, struct QsfNodeIterate *qsfiter, QsfParam *params)
Definition: qsf-xml.c:116
QsfMetadata_s::lister
xmlNodePtr lister
Definition: qsf-xml.h:505
DEBUG
#define DEBUG(format, args...)
Definition: qoflog.h:208
QsfMetadata_s::child_node
xmlNodePtr child_node
Definition: qsf-xml.h:493
qof-backend-qsf.h
QSF API - Backend, maps, objects and configuration.
MAP_CALCULATE_TAG
#define MAP_CALCULATE_TAG
Definition: qsf-xml.h:251
is_qsf_object_with_map_be
gboolean is_qsf_object_with_map_be(gchar *map_path, QsfParam *params)
Validate a QSF file and a selected QSF map.
Definition: qsf-xml-map.c:240
QsfMetadata_s::qsf_parameter_hash
GHashTable * qsf_parameter_hash
Definition: qsf-xml.h:484
QSF_INVALID_OBJECT
Definition: qsf-xml.h:460
is_qsf_map_be
gboolean is_qsf_map_be(QsfParam *params)
Validate a QSF map file.
Definition: qsf-xml-map.c:320
is_qsf_map
gboolean is_qsf_map(const gchar *path)
Validate a QSF map file.
Definition: qsf-xml-map.c:372
QSF_XSD_TIME
#define QSF_XSD_TIME
Definition: qsf-xml.h:414
QsfValidates_s::incoming_count
guint incoming_count
Definition: qsf-xml.h:581
QSF_CONDITIONAL_ELSE
#define QSF_CONDITIONAL_ELSE
Definition: qsf-xml.h:358
QSF_OBJECT_SCHEMA
#define QSF_OBJECT_SCHEMA
Definition: qsf-xml.h:420
qsf_is_element
gint qsf_is_element(xmlNodePtr a, xmlNsPtr ns, gchar *c)
shorthand function
Definition: qsf-xml.c:55
QsfMetadata_s::output_node
xmlNodePtr output_node
Definition: qsf-xml.h:499
QSF_QOF_VERSION
#define QSF_QOF_VERSION
Definition: qsf-xml.h:70
QsfMetadata_s::filepath
gchar * filepath
Definition: qsf-xml.h:533
QsfObject_s
Holds a description of the QofObject.
Definition: qsf-xml.h:63
QOF_FATAL
#define QOF_FATAL
general error value
Definition: qoferror.h:131
QSF_CONDITIONAL
#define QSF_CONDITIONAL
Definition: qsf-xml.h:322
safe_strcmp
gint safe_strcmp(const gchar *da, const gchar *db)
Definition: qofutil.c:72
QSF_MAP_SCHEMA
#define QSF_MAP_SCHEMA
Definition: qsf-xml.h:423
qsf_object_convert
xmlDocPtr qsf_object_convert(xmlDocPtr mapDoc, xmlNodePtr qsf_root, QsfParam *params)
Convert between QSF objects.
Definition: qsf-xml-map.c:954
qsf_book_node_handler
void qsf_book_node_handler(xmlNodePtr child, xmlNsPtr qsf_ns, QsfParam *params)
Book and book-guid node handler.
Definition: qsf-xml.c:424
QsfValidates_s::object_table
GHashTable * object_table
Definition: qsf-xml.h:565
QSF_CALCULATED_OBJECT
Definition: qsf-xml.h:458
QsfMetadata_s::object_set
QsfObject * object_set
Definition: qsf-xml.h:474
MAP_OBJECT_TAG
#define MAP_OBJECT_TAG
Definition: qsf-xml.h:240
QSF_DATE_LENGTH
#define QSF_DATE_LENGTH
Definition: qsf-xml.h:91
ENTER
#define ENTER(format, args...)
Definition: qoflog.h:217
QSF_OPTION
#define QSF_OPTION
Definition: qsf-xml.h:366
QofLogModule
const gchar * QofLogModule
Definition: qofid.h:85
QSF_XML_VERSION
#define QSF_XML_VERSION
Definition: qsf-xml.h:107
MAP_NAME_ATTR
#define MAP_NAME_ATTR
Definition: qsf-xml.h:270