QOF
0.7.5
|
00001 /*************************************************************************** 00002 * qsf-xml-map.c 00003 * 00004 * Sat Jan 1 07:31:55 2005 00005 * Copyright 2005-2006 Neil Williams 00006 * linux@codehelp.co.uk 00007 ****************************************************************************/ 00008 /* 00009 * This program is free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 * GNU General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU General Public License 00020 * along with this program; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00022 */ 00023 00024 #include "config.h" 00025 #include <glib.h> 00026 #include <libxml/xmlversion.h> 00027 #include <libxml/xmlmemory.h> 00028 #include <libxml/tree.h> 00029 #include <libxml/parser.h> 00030 #include <libxml/xmlschemas.h> 00031 #include "qof.h" 00032 #include "qof-backend-qsf.h" 00033 #include "qsf-xml.h" 00034 #include "qsf-dir.h" 00035 00036 static QofLogModule log_module = QOF_MOD_QSF; 00037 00038 static void 00039 qsf_date_default_handler (const gchar * default_name, 00040 GHashTable * qsf_default_hash, 00041 xmlNodePtr parent_tag, xmlNodePtr import_node, xmlNsPtr ns) 00042 { 00043 xmlNodePtr output_parent; 00044 time_t *qsf_time; 00045 gchar date_as_string[QSF_DATE_LENGTH]; 00046 00047 output_parent = xmlAddChild (parent_tag, xmlNewNode (ns, 00048 xmlGetProp (import_node, BAD_CAST QSF_OBJECT_TYPE))); 00049 xmlNewProp (output_parent, BAD_CAST QSF_OBJECT_TYPE, 00050 xmlGetProp (import_node, BAD_CAST MAP_VALUE_ATTR)); 00051 qsf_time = 00052 (time_t *) g_hash_table_lookup (qsf_default_hash, default_name); 00053 strftime (date_as_string, QSF_DATE_LENGTH, QSF_XSD_TIME, 00054 gmtime (qsf_time)); 00055 xmlNodeAddContent (output_parent, BAD_CAST date_as_string); 00056 } 00057 00058 static void 00059 qsf_string_default_handler (const gchar * default_name, 00060 GHashTable * qsf_default_hash, 00061 xmlNodePtr parent_tag, xmlNodePtr import_node, xmlNsPtr ns) 00062 { 00063 xmlNodePtr node; 00064 xmlChar *output; 00065 00066 node = xmlAddChild (parent_tag, 00067 xmlNewNode (ns, 00068 xmlGetProp (import_node, BAD_CAST QSF_OBJECT_TYPE))); 00069 xmlNewProp (node, BAD_CAST QSF_OBJECT_TYPE, 00070 xmlGetProp (import_node, BAD_CAST MAP_VALUE_ATTR)); 00071 output = 00072 (xmlChar *) g_hash_table_lookup (qsf_default_hash, default_name); 00073 xmlNodeAddContent (node, output); 00074 } 00075 00076 static void 00077 qsf_map_validation_handler (xmlNodePtr child, xmlNsPtr ns, 00078 QsfValidator * valid) 00079 { 00080 xmlChar *qof_version, *obj_type; 00081 gboolean match, is_registered; 00082 gchar *buff; 00083 xmlNodePtr child_node; 00084 QsfStatus type, incoming_type; 00085 00086 match = FALSE; 00087 buff = NULL; 00088 is_registered = FALSE; 00089 type = QSF_NO_OBJECT; 00090 if (qsf_is_element (child, ns, MAP_DEFINITION_TAG)) 00091 { 00092 qof_version = xmlGetProp (child, BAD_CAST MAP_QOF_VERSION); 00093 buff = g_strdup_printf ("%i", QSF_QOF_VERSION); 00094 if (xmlStrcmp (qof_version, BAD_CAST buff) != 0) 00095 { 00096 PERR (" Wrong QOF_VERSION in map '%s', should be %s", 00097 qof_version, buff); 00098 valid->error_state = QOF_FATAL; 00099 g_free (buff); 00100 return; 00101 } 00102 g_free (buff); 00103 for (child_node = child->children; child_node != NULL; 00104 child_node = child_node->next) 00105 { 00106 if (qsf_is_element (child_node, ns, MAP_DEFINE_TAG)) 00107 { 00108 obj_type = xmlGetProp (child_node, MAP_E_TYPE); 00109 type = QSF_DEFINED_OBJECT; 00110 is_registered = qof_class_is_registered (obj_type); 00111 if (is_registered) 00112 { 00113 type = QSF_REGISTERED_OBJECT; 00114 } 00115 g_hash_table_insert (valid->map_table, obj_type, 00116 GINT_TO_POINTER (type)); 00117 } 00118 } 00119 } 00120 if (qsf_is_element (child, ns, MAP_OBJECT_TAG)) 00121 { 00122 obj_type = xmlGetProp (child, BAD_CAST MAP_TYPE_ATTR); 00123 /* check each listed object is either registered or calculated. */ 00124 type = 00125 GPOINTER_TO_INT (g_hash_table_lookup 00126 (valid->map_table, obj_type)); 00127 switch (type) 00128 { 00129 case QSF_DEFINED_OBJECT: 00130 /* we have a calculation for an unregistered object. */ 00131 /* Ignore the calculation that exists to support bidirectional maps. */ 00132 /* Check that the incoming QSF contains data for this object */ 00133 { 00134 /* lookup the same object in QSF object_table */ 00135 incoming_type = 00136 GPOINTER_TO_INT (g_hash_table_lookup 00137 (valid->object_table, obj_type)); 00138 switch (incoming_type) 00139 { 00140 case QSF_DEFINED_OBJECT: 00141 { 00142 valid->incoming_count++; 00143 g_hash_table_insert (valid->map_table, obj_type, 00144 GINT_TO_POINTER (type)); 00145 break; /* good, proceed. */ 00146 } 00147 default: 00148 { 00149 PERR (" Missing data: %s", obj_type); 00150 type = QSF_INVALID_OBJECT; 00151 break; 00152 } 00153 } 00154 break; 00155 } 00156 case QSF_REGISTERED_OBJECT: /* use this calculation. */ 00157 { 00158 type = QSF_CALCULATED_OBJECT; 00159 valid->map_calculated_count++; 00160 valid->qof_registered_count++; 00161 /* store the result */ 00162 g_hash_table_insert (valid->map_table, obj_type, 00163 GINT_TO_POINTER (type)); 00164 break; 00165 } 00166 default: 00167 { 00168 type = QSF_INVALID_OBJECT; 00169 break; 00170 } 00171 } 00172 PINFO (" final type=%s result=%d", obj_type, type); 00173 if (type == QSF_INVALID_OBJECT) 00174 { 00175 valid->error_state = QOF_FATAL; 00176 } 00177 } 00178 } 00179 00180 static QofErrorId 00181 check_qsf_object_with_map_internal (xmlDocPtr map_doc, xmlDocPtr doc) 00182 { 00183 xmlNodePtr map_root, object_root; 00184 struct QsfNodeIterate qsfiter; 00185 QsfValidator valid; 00186 xmlNsPtr map_ns; 00187 00188 valid.map_table = g_hash_table_new (g_str_hash, g_str_equal); 00189 valid.object_table = g_hash_table_new (g_str_hash, g_str_equal); 00190 map_root = xmlDocGetRootElement (map_doc); 00191 object_root = xmlDocGetRootElement (doc); 00192 valid.map_calculated_count = 0; 00193 valid.valid_object_count = 0; 00194 valid.qof_registered_count = 0; 00195 valid.incoming_count = 0; 00196 valid.error_state = QOF_SUCCESS; 00197 map_ns = map_root->ns; 00198 qsfiter.ns = object_root->ns; 00199 qsf_valid_foreach (object_root, qsf_object_validation_handler, 00200 &qsfiter, &valid); 00201 qsfiter.ns = map_ns; 00202 qsf_valid_foreach (map_root, qsf_map_validation_handler, &qsfiter, 00203 &valid); 00204 if (valid.error_state != QOF_SUCCESS) 00205 { 00206 PINFO (" Map is wrong. Trying the next map."); 00207 g_hash_table_destroy (valid.object_table); 00208 g_hash_table_destroy (valid.map_table); 00209 return valid.error_state; 00210 } 00211 /* check all counted objects are valid: 00212 Objects to be calculated must also be registered 00213 so that new objects can be created and populated 00214 from the incoming data: qof_registered_count > 0 00215 The incoming data must contain valid objects - 00216 not an empty QofBook: valid_object_count > 0 00217 The map must contain at least some calculations: 00218 map_calculated_count > 0 00219 */ 00220 if ((valid.qof_registered_count < 1) 00221 || (valid.map_calculated_count < 1) 00222 || (valid.valid_object_count < 1) 00223 || (valid.incoming_count < g_hash_table_size (valid.object_table))) 00224 { 00225 PINFO 00226 (" Map is wrong. map:%d object:%d reg:%d incoming:%d size:%d", 00227 valid.map_calculated_count, valid.valid_object_count, 00228 valid.qof_registered_count, valid.incoming_count, 00229 g_hash_table_size (valid.object_table)); 00230 g_hash_table_destroy (valid.object_table); 00231 g_hash_table_destroy (valid.map_table); 00232 return valid.error_state; 00233 } 00234 g_hash_table_destroy (valid.object_table); 00235 g_hash_table_destroy (valid.map_table); 00236 return QOF_SUCCESS; 00237 } 00238 00239 gboolean 00240 is_qsf_object_with_map_be (gchar * map_file, QsfParam * params) 00241 { 00242 xmlDocPtr doc, map_doc; 00243 QofErrorId result; 00244 gchar *path, *map_path; 00245 00246 g_return_val_if_fail ((params != NULL), FALSE); 00247 path = g_strdup (params->filepath); 00248 map_path = g_strdup_printf ("%s/%s", QSF_SCHEMA_DIR, map_file); 00249 PINFO (" checking map file '%s'", map_path); 00250 if (path == NULL) 00251 { 00252 qof_error_set_be (params->be, qof_error_register 00253 (_("The QSF XML file '%s' could not be found."), TRUE)); 00254 return FALSE; 00255 } 00256 doc = xmlParseFile (path); 00257 if (doc == NULL) 00258 { 00259 qof_error_set_be (params->be, qof_error_register 00260 (_("There was an error parsing the file '%s'."), TRUE)); 00261 return FALSE; 00262 } 00263 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) 00264 { 00265 qof_error_set_be (params->be, qof_error_register 00266 (_("Invalid QSF Object file! The QSF object file '%s' " 00267 " failed to validate against the QSF object schema. " 00268 "The XML structure of the file is either not well-formed " 00269 "or the file contains illegal data."), TRUE)); 00270 return FALSE; 00271 } 00272 if (map_path == NULL) 00273 { 00274 qof_error_set_be (params->be, qof_error_register 00275 (_("The QSF map file '%s' could not be found."), TRUE)); 00276 return FALSE; 00277 } 00278 map_doc = xmlParseFile (map_path); 00279 if (map_doc == NULL) 00280 { 00281 qof_error_set_be (params->be, qof_error_register 00282 (_("There was an error parsing the file '%s'."), TRUE)); 00283 return FALSE; 00284 } 00285 result = check_qsf_object_with_map_internal (map_doc, doc); 00286 return (result == QOF_SUCCESS) ? TRUE : FALSE; 00287 } 00288 00289 gboolean 00290 is_qsf_object_with_map (const gchar * path, gchar * map_file) 00291 { 00292 xmlDocPtr doc, map_doc; 00293 QofErrorId result; 00294 gchar *map_path; 00295 00296 map_path = g_strdup_printf ("%s/%s", QSF_SCHEMA_DIR, map_file); 00297 if (path == NULL) 00298 { 00299 return FALSE; 00300 } 00301 doc = xmlParseFile (path); 00302 if (doc == NULL) 00303 { 00304 return FALSE; 00305 } 00306 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) 00307 { 00308 return FALSE; 00309 } 00310 if (map_path == NULL) 00311 { 00312 return FALSE; 00313 } 00314 map_doc = xmlParseFile (map_path); 00315 result = check_qsf_object_with_map_internal (map_doc, doc); 00316 return (result == QOF_SUCCESS) ? TRUE : FALSE; 00317 } 00318 00319 gboolean 00320 is_qsf_map_be (QsfParam * params) 00321 { 00322 xmlDocPtr doc; 00323 struct QsfNodeIterate qsfiter; 00324 QsfValidator valid; 00325 xmlNodePtr map_root; 00326 xmlNsPtr map_ns; 00327 gchar *path; 00328 00329 g_return_val_if_fail ((params != NULL), FALSE); 00330 path = g_strdup (params->filepath); 00331 if (path == NULL) 00332 { 00333 qof_error_set_be (params->be, qof_error_register 00334 (_("The QSF XML file '%s' could not be found."), TRUE)); 00335 return FALSE; 00336 } 00337 doc = xmlParseFile (path); 00338 if (doc == NULL) 00339 { 00340 qof_error_set_be (params->be, qof_error_register 00341 (_("There was an error parsing the file '%s'."), TRUE)); 00342 return FALSE; 00343 } 00344 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_MAP_SCHEMA, doc)) 00345 { 00346 qof_error_set_be (params->be, 00347 qof_error_register ( 00348 _("Invalid QSF Map file! The QSF map file " 00349 "failed to validate against the QSF map schema. " 00350 "The XML structure of the file is either not well-formed " 00351 "or the file contains illegal data."), FALSE)); 00352 return FALSE; 00353 } 00354 map_root = xmlDocGetRootElement (doc); 00355 map_ns = map_root->ns; 00356 qsfiter.ns = map_ns; 00357 valid.object_table = g_hash_table_new (g_str_hash, g_str_equal); 00358 valid.map_table = g_hash_table_new (g_str_hash, g_str_equal); 00359 valid.error_state = QOF_SUCCESS; 00360 qsf_valid_foreach (map_root, qsf_map_validation_handler, 00361 &qsfiter, &valid); 00362 if (valid.error_state != QOF_SUCCESS) 00363 { 00364 g_hash_table_destroy (valid.object_table); 00365 return FALSE; 00366 } 00367 g_hash_table_destroy (valid.object_table); 00368 return TRUE; 00369 } 00370 00371 gboolean 00372 is_qsf_map (const gchar * path) 00373 { 00374 xmlDocPtr doc; 00375 struct QsfNodeIterate qsfiter; 00376 QsfValidator valid; 00377 xmlNodePtr map_root; 00378 xmlNsPtr map_ns; 00379 00380 g_return_val_if_fail ((path != NULL), FALSE); 00381 if (path == NULL) 00382 { 00383 return FALSE; 00384 } 00385 doc = xmlParseFile (path); 00386 if (doc == NULL) 00387 { 00388 return FALSE; 00389 } 00390 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_MAP_SCHEMA, doc)) 00391 { 00392 return FALSE; 00393 } 00394 map_root = xmlDocGetRootElement (doc); 00395 map_ns = map_root->ns; 00396 qsfiter.ns = map_ns; 00397 valid.error_state = QOF_SUCCESS; 00398 valid.map_table = g_hash_table_new (g_str_hash, g_str_equal); 00399 qsf_valid_foreach (map_root, qsf_map_validation_handler, 00400 &qsfiter, &valid); 00401 if (valid.error_state != QOF_SUCCESS) 00402 { 00403 g_hash_table_destroy (valid.map_table); 00404 return FALSE; 00405 } 00406 g_hash_table_destroy (valid.map_table); 00407 return TRUE; 00408 } 00409 00410 static void 00411 qsf_map_default_handler (xmlNodePtr child, xmlNsPtr ns, QsfParam * params) 00412 { 00413 xmlChar *qsf_enum; 00414 gchar *iterate; 00415 QofErrorId bad_map; 00416 00417 g_return_if_fail (params->qsf_define_hash != NULL); 00418 iterate = NULL; 00419 bad_map = qof_error_register 00420 (_("The selected QSF map '%s' contains unusable or " 00421 "missing data. This is usually because not all the " 00422 "required parameters for the defined objects have " 00423 "calculations described in the map."), TRUE); 00424 if (qsf_is_element (child, ns, MAP_DEFINE_TAG)) 00425 { 00426 iterate = xmlGetProp (child, MAP_ITERATE_ATTR); 00427 if ((qof_util_bool_to_int (iterate) == 1) && 00428 (qof_class_is_registered 00429 (xmlGetProp (child, BAD_CAST MAP_E_TYPE)))) 00430 { 00431 params->qof_foreach = xmlGetProp (child, BAD_CAST MAP_E_TYPE); 00432 PINFO (" iterating over '%s' objects", params->qof_foreach); 00433 } 00434 if (NULL == g_hash_table_lookup (params->qsf_define_hash, 00435 xmlGetProp (child, BAD_CAST MAP_E_TYPE))) 00436 { 00437 g_hash_table_insert (params->qsf_define_hash, 00438 xmlGetProp (child, BAD_CAST MAP_E_TYPE), 00439 params->child_node); 00440 } 00441 else 00442 { 00443 qof_error_set_be (params->be, bad_map); 00444 PERR (" ERR_QSF_BAD_MAP set"); 00445 return; 00446 } 00447 } 00448 if (qsf_is_element (child, ns, MAP_DEFAULT_TAG)) 00449 { 00450 if (qsf_strings_equal 00451 (xmlGetProp (child, BAD_CAST MAP_TYPE_ATTR), MAP_ENUM_TYPE)) 00452 { 00453 qsf_enum = xmlNodeGetContent (child); 00455 PERR (" enum todo incomplete"); 00459 if (NULL == g_hash_table_lookup (params->qsf_default_hash, 00460 xmlNodeGetContent (child))) 00461 { 00462 g_hash_table_insert (params->qsf_default_hash, 00463 xmlNodeGetContent (child), child); 00464 } 00465 else 00466 { 00467 qof_error_set_be (params->be, bad_map); 00468 PERR (" ERR_QSF_BAD_MAP set"); 00469 return; 00470 } 00471 } 00473 else 00474 { 00475 if (NULL == g_hash_table_lookup (params->qsf_default_hash, 00476 xmlGetProp (child, BAD_CAST MAP_NAME_ATTR))) 00477 { 00478 g_hash_table_insert (params->qsf_default_hash, 00479 xmlGetProp (child, BAD_CAST MAP_NAME_ATTR), child); 00480 } 00481 else 00482 /* if(0 != xmlHashAddEntry(params->default_map, 00483 xmlGetProp(child_node, MAP_NAME_ATTR), child_node))*/ 00484 { 00485 qof_error_set_be (params->be, bad_map); 00486 PERR (" ERR_QSF_BAD_MAP set"); 00487 return; 00488 } 00489 } 00490 } 00491 } 00492 00493 static void 00494 qsf_map_top_node_handler (xmlNodePtr child, xmlNsPtr ns, 00495 QsfParam * params) 00496 { 00497 xmlChar *qof_version; 00498 gchar *buff; 00499 struct QsfNodeIterate qsfiter; 00500 00501 if (!params->qsf_define_hash) 00502 return; 00503 if (!params->qsf_default_hash) 00504 return; 00505 ENTER (" map top node child=%s", child->name); 00506 buff = NULL; 00507 if (qsf_is_element (child, ns, MAP_DEFINITION_TAG)) 00508 { 00509 qof_version = xmlGetProp (child, BAD_CAST MAP_QOF_VERSION); 00510 buff = g_strdup_printf ("%i", QSF_QOF_VERSION); 00511 if (xmlStrcmp (qof_version, BAD_CAST buff) != 0) 00512 { 00513 qof_error_set_be (params->be, qof_error_register( 00514 _("The QSF Map file '%s' was written for a different " 00515 "version of QOF. It may need to be modified to work with " 00516 "your current QOF installation."), TRUE)); 00517 LEAVE (" BAD QOF VERSION"); 00518 return; 00519 } 00520 qsfiter.ns = ns; 00521 qsf_node_foreach (child, qsf_map_default_handler, &qsfiter, params); 00522 } 00523 LEAVE (" "); 00524 } 00525 00526 static char * 00527 qsf_else_set_value (xmlNodePtr parent, gchar * content, 00528 xmlNsPtr map_ns) 00529 { 00530 xmlNodePtr cur_node; 00531 00532 content = NULL; 00533 for (cur_node = parent->children; cur_node != NULL; 00534 cur_node = cur_node->next) 00535 { 00536 if (qsf_is_element (cur_node, map_ns, QSF_CONDITIONAL_SET)) 00537 { 00538 content = (gchar *) xmlNodeGetContent (cur_node); 00539 return content; 00540 } 00541 } 00542 return NULL; 00543 } 00544 00545 /* Handles the set tag in the map. 00546 This function will be overhauled once inside QOF 00547 QOF hook required for "Lookup in the receiving application" 00548 */ 00549 static gchar * 00550 qsf_set_handler (xmlNodePtr parent, GHashTable * default_hash, 00551 gchar * content, QsfParam * params) 00552 { 00553 xmlNodePtr cur_node, lookup_node; 00554 00555 ENTER (" lookup problem"); 00556 content = NULL; 00557 for (cur_node = parent->children; cur_node != NULL; 00558 cur_node = cur_node->next) 00559 { 00560 if (qsf_is_element (cur_node, params->map_ns, QSF_CONDITIONAL_SET)) 00561 { 00562 content = (gchar *) xmlGetProp (cur_node, BAD_CAST QSF_OPTION); 00563 if (qsf_strings_equal (xmlGetProp (cur_node, 00564 BAD_CAST QSF_OPTION), "qsf_lookup_string")) 00565 { 00566 lookup_node = 00567 (xmlNodePtr) g_hash_table_lookup (default_hash, 00568 xmlNodeGetContent (cur_node)); 00569 content = 00570 (gchar *) xmlGetProp (lookup_node, 00571 BAD_CAST MAP_VALUE_ATTR); 00573 /* Find by name, get GUID, return GUID as string. */ 00574 g_message ("Lookup %s in the receiving application\n", 00575 content); 00576 LEAVE (" todo"); 00577 return content; 00578 } 00579 if (content) 00580 { 00581 lookup_node = 00582 (xmlNodePtr) g_hash_table_lookup (default_hash, 00583 xmlNodeGetContent (cur_node)); 00584 content = 00585 (gchar *) xmlGetProp (lookup_node, BAD_CAST "value"); 00586 return content; 00587 } 00588 content = (gchar *) xmlGetProp (parent, BAD_CAST "boolean"); 00589 if (!content) 00590 { 00592 lookup_node = 00593 (xmlNodePtr) g_hash_table_lookup (params-> 00594 qsf_parameter_hash, 00595 xmlGetProp (parent->parent, BAD_CAST MAP_TYPE_ATTR)); 00596 if (lookup_node) 00597 { 00598 return (gchar *) xmlNodeGetContent (lookup_node); 00599 } 00600 LEAVE (" check arguments"); 00601 return (gchar *) xmlNodeGetContent (cur_node); 00602 } 00603 } 00604 } 00605 LEAVE (" null"); 00606 return NULL; 00607 } 00608 00609 static void 00610 qsf_calculate_else (xmlNodePtr param_node, xmlNodePtr child, 00611 QsfParam * params) 00612 { 00613 xmlNodePtr export_node; 00614 xmlChar *output_content, *object_data; 00615 00616 if (qsf_is_element (param_node, params->map_ns, QSF_CONDITIONAL_ELSE)) 00617 { 00618 if (params->boolean_calculation_done == 0) 00619 { 00620 output_content = object_data = NULL; 00621 output_content = BAD_CAST qsf_set_handler (param_node, 00622 params-> 00623 qsf_default_hash, (gchar *) output_content, params); 00624 if (output_content == NULL) 00625 { 00626 output_content = 00627 xmlGetProp (param_node, BAD_CAST MAP_TYPE_ATTR); 00628 object_data = 00629 BAD_CAST qsf_else_set_value (param_node, 00630 (gchar *) output_content, params->map_ns); 00631 output_content = 00632 BAD_CAST xmlGetProp ((xmlNodePtr) 00633 g_hash_table_lookup (params-> 00634 qsf_default_hash, 00635 object_data), BAD_CAST MAP_VALUE_ATTR); 00636 } 00637 if (object_data != NULL) 00638 { 00639 export_node = 00640 (xmlNodePtr) g_hash_table_lookup (params-> 00641 qsf_parameter_hash, 00642 xmlGetProp (params-> 00643 child_node, BAD_CAST QSF_OBJECT_TYPE)); 00644 object_data = xmlNodeGetContent (export_node); 00645 } 00646 if (output_content != NULL) 00647 { 00648 object_data = output_content; 00649 } 00650 export_node = 00651 xmlAddChild (params->lister, 00652 xmlNewNode (params->qsf_ns, 00653 xmlGetProp (child, BAD_CAST QSF_OBJECT_TYPE))); 00654 xmlNewProp (export_node, BAD_CAST QSF_OBJECT_TYPE, 00655 xmlGetProp (child, BAD_CAST MAP_VALUE_ATTR)); 00656 xmlNodeAddContent (export_node, object_data); 00657 params->boolean_calculation_done = 1; 00658 } 00659 } 00660 } 00661 00662 static void 00663 qsf_set_format_value (xmlChar * format, gchar * qsf_time_now_as_string, 00664 xmlNodePtr cur_node, QsfParam * params) 00665 { 00666 gint result; 00667 xmlChar *content; 00668 time_t *output; 00669 struct tm *tmp; 00670 time_t tester; 00671 xmlNodePtr kl; 00672 regex_t reg; 00673 00676 result = 0; 00677 if (format == NULL) 00678 { 00679 return; 00680 } 00681 ENTER (" "); 00682 content = xmlNodeGetContent (cur_node); 00683 output = 00684 (time_t *) g_hash_table_lookup (params->qsf_default_hash, content); 00685 if (!output) 00686 { 00689 tester = time (NULL); 00690 tmp = gmtime (&tester); 00693 kl = (xmlNodePtr) g_hash_table_lookup (params->qsf_parameter_hash, 00694 content); 00695 if (!kl) 00696 { 00697 LEAVE (" no suitable date set."); 00698 return; 00699 } 00701 strptime ((char *) xmlNodeGetContent (kl), QSF_XSD_TIME, tmp); 00702 if (!tmp) 00703 { 00704 LEAVE (" empty date field in QSF object.\n"); 00705 return; 00706 } 00707 tester = mktime (tmp); 00708 output = &tester; 00709 } 00710 result = regcomp (®, "%[a-zA-Z]", REG_EXTENDED | REG_NOSUB); 00711 result = regexec (®, (gchar *) format, (size_t) 0, NULL, 0); 00712 if (result == REG_NOMATCH) 00713 { 00714 format = BAD_CAST "%F"; 00715 } 00716 regfree (®); 00717 /* QSF_DATE_LENGTH preset for all internal and QSF_XSD_TIME string formats. */ 00718 strftime (qsf_time_now_as_string, QSF_DATE_LENGTH, (char *) format, 00719 gmtime (output)); 00720 LEAVE (" ok"); 00721 } 00722 00723 static void 00724 qsf_boolean_set_value (xmlNodePtr parent, QsfParam * params, 00725 gchar * content, xmlNsPtr map_ns) 00726 { 00727 xmlNodePtr cur_node; 00728 xmlChar *boolean_name; 00729 00730 boolean_name = NULL; 00731 for (cur_node = parent->children; cur_node != NULL; 00732 cur_node = cur_node->next) 00733 { 00734 if (qsf_is_element (cur_node, map_ns, QSF_CONDITIONAL_SET)) 00735 { 00736 boolean_name = 00737 xmlGetProp (cur_node, BAD_CAST QSF_FORMATTING_OPTION); 00738 qsf_set_format_value (boolean_name, content, cur_node, params); 00739 } 00740 } 00741 } 00742 00743 static void 00744 qsf_calculate_conditional (xmlNodePtr param_node, xmlNodePtr child, 00745 QsfParam * params) 00746 { 00747 xmlNodePtr export_node; 00748 xmlChar *output_content; 00749 00750 output_content = NULL; 00751 if (qsf_is_element (param_node, params->map_ns, QSF_CONDITIONAL)) 00752 { 00753 if (params->boolean_calculation_done == 0) 00754 { 00755 /* set handler */ 00756 output_content = 00757 BAD_CAST qsf_set_handler (param_node, 00758 params->qsf_default_hash, 00759 (gchar *) output_content, params); 00760 /* If the 'if' contains a boolean that has a default value */ 00761 if (output_content == NULL) 00762 { 00763 if (NULL != 00764 xmlGetProp (param_node, BAD_CAST QSF_BOOLEAN_DEFAULT)) 00765 { 00766 output_content = 00767 xmlGetProp ((xmlNodePtr) 00768 g_hash_table_lookup (params-> 00769 qsf_default_hash, 00770 xmlGetProp 00771 (param_node, 00772 BAD_CAST 00773 QSF_BOOLEAN_DEFAULT)), 00774 BAD_CAST MAP_VALUE_ATTR); 00775 } 00776 /* Is the default set to true? */ 00777 if (0 == 00778 qsf_compare_tag_strings (output_content, 00779 QSF_XML_BOOLEAN_TEST)) 00780 { 00781 qsf_boolean_set_value (param_node, params, 00782 (gchar *) output_content, params->map_ns); 00783 export_node = 00784 xmlAddChild (params->lister, 00785 xmlNewNode (params->qsf_ns, 00786 xmlGetProp (child, BAD_CAST QSF_OBJECT_TYPE))); 00787 xmlNewProp (export_node, BAD_CAST QSF_OBJECT_TYPE, 00788 xmlGetProp (child, BAD_CAST MAP_VALUE_ATTR)); 00789 xmlNodeAddContent (export_node, output_content); 00790 params->boolean_calculation_done = 1; 00791 } 00792 } 00793 } 00794 } 00795 } 00796 00797 static void 00798 qsf_add_object_tag (QsfParam * params, gint count) 00799 { 00800 xmlNodePtr extra_node; 00801 GString *str; 00802 xmlChar *property; 00803 00804 str = g_string_new (" "); 00805 g_string_printf (str, "%i", count); 00806 extra_node = NULL; 00807 extra_node = xmlAddChild (params->output_node, 00808 xmlNewNode (params->qsf_ns, BAD_CAST QSF_OBJECT_TAG)); 00809 xmlNewProp (extra_node, BAD_CAST QSF_OBJECT_TYPE, 00810 xmlGetProp (params->convert_node, BAD_CAST QSF_OBJECT_TYPE)); 00811 property = xmlCharStrdup (str->str); 00812 xmlNewProp (extra_node, BAD_CAST QSF_OBJECT_COUNT, property); 00813 params->lister = extra_node; 00814 } 00815 00816 static gint 00817 identify_source_func (gconstpointer qsf_object, gconstpointer map) 00818 { 00819 PINFO (" qsf_object=%s, map=%s", 00820 ((QsfObject *) qsf_object)->object_type, (QofIdType) map); 00821 return safe_strcmp (((QsfObject *) qsf_object)->object_type, 00822 (QofIdType) map); 00823 } 00824 00825 static void 00826 qsf_map_calculate_output (xmlNodePtr param_node, xmlNodePtr child, 00827 QsfParam * params) 00828 { 00829 xmlNodePtr export_node; 00830 xmlChar *output_content; 00831 xmlNodePtr input_node; 00832 GList *source; 00833 00834 output_content = xmlNodeGetContent (param_node); 00835 DEBUG (" %s", output_content); 00836 /* source refers to the source object that provides the data */ 00837 source = g_list_find_custom (params->qsf_object_list, 00838 BAD_CAST xmlGetProp (param_node, 00839 MAP_OBJECT_ATTR), identify_source_func); 00840 PINFO (" checking %s", BAD_CAST xmlGetProp (param_node, 00841 MAP_OBJECT_ATTR)); 00842 if (!source) 00843 { 00844 DEBUG (" no source found in list."); 00845 return; 00846 } 00847 params->object_set = source->data; 00848 input_node = g_hash_table_lookup (params->object_set->parameters, 00849 output_content); 00850 DEBUG (" node_value=%s, content=%s", 00851 xmlGetProp (child, BAD_CAST MAP_VALUE_ATTR), 00852 xmlNodeGetContent (input_node)); 00853 export_node = xmlAddChild (params->lister, xmlNewNode (params->qsf_ns, 00854 xmlGetProp (child, BAD_CAST QSF_OBJECT_TYPE))); 00855 xmlNewProp (export_node, BAD_CAST QSF_OBJECT_TYPE, 00856 xmlGetProp (child, BAD_CAST MAP_VALUE_ATTR)); 00857 xmlNodeAddContent (export_node, xmlNodeGetContent (input_node)); 00858 } 00859 00860 static void 00861 qsf_map_object_handler (xmlNodePtr child, xmlNsPtr ns, QsfParam * params) 00862 { 00863 xmlNodePtr param_node; 00864 xmlNsPtr map_ns, qsf_ns; 00865 gint result; 00866 00867 map_ns = ns; 00868 qsf_ns = params->qsf_ns; 00869 param_node = NULL; 00870 result = 0; 00871 if (child == NULL) 00872 { 00873 return; 00874 } 00875 if (ns == NULL) 00876 { 00877 return; 00878 } 00879 params->boolean_calculation_done = 0; 00880 00881 if (qsf_is_element (child, map_ns, MAP_CALCULATE_TAG)) 00882 { 00883 params->boolean_calculation_done = 0; 00884 /* read the child nodes to prepare the calculation. */ 00885 for (param_node = child->children; param_node != NULL; 00886 param_node = param_node->next) 00887 { 00888 if (qsf_is_element (param_node, map_ns, QSF_CONDITIONAL_SET)) 00889 { 00890 /* Map the pre-defined defaults */ 00891 if (0 == 00892 qsf_compare_tag_strings (xmlNodeGetContent 00893 (param_node), "qsf_enquiry_date")) 00894 { 00895 qsf_string_default_handler ("qsf_enquiry_date", 00896 params->qsf_default_hash, 00897 params->lister, child, qsf_ns); 00898 } 00899 if (0 == 00900 qsf_compare_tag_strings (xmlNodeGetContent 00901 (param_node), "qsf_time_now")) 00902 { 00903 qsf_date_default_handler ("qsf_time_now", 00904 params->qsf_default_hash, 00905 params->lister, child, qsf_ns); 00906 } 00907 if (0 == 00908 qsf_compare_tag_strings (xmlNodeGetContent 00909 (param_node), "qsf_time_string")) 00910 { 00911 qsf_string_default_handler ("qsf_time_string", 00912 params->qsf_default_hash, 00913 params->lister, child, qsf_ns); 00914 } 00915 qsf_map_calculate_output (param_node, child, params); 00916 } 00917 qsf_calculate_conditional (param_node, child, params); 00918 qsf_calculate_else (param_node, child, params); 00919 } 00920 /* calculate_map currently not in use */ 00921 /* ensure uniqueness of the key before re-instating */ 00922 /* result = xmlHashAddEntry2(calculate_map, 00923 xmlGetProp(child_node, MAP_TYPE_ATTR), 00924 xmlGetProp(child_node, MAP_VALUE_ATTR), child_node); 00925 if(result != 0) { 00926 printf("add entry to calculate hash failed. %s\t%s\t%s.\n", 00927 xmlGetProp(child_node, MAP_TYPE_ATTR), 00928 xmlGetProp(child_node, MAP_VALUE_ATTR), child_node->name); 00929 return; 00930 } 00931 00932 is_qsf_object_with_map(path, map_path); 00933 */ 00934 } 00935 } 00936 00937 static void 00938 iterator_cb (xmlNodePtr child, xmlNsPtr ns, QsfParam * params) 00939 { 00940 gchar *object_name; 00941 00942 /* count the number of iterators in the QSF file */ 00943 if (qsf_is_element (child, ns, QSF_OBJECT_TAG)) 00944 { 00945 object_name = xmlGetProp (child, QSF_OBJECT_TYPE); 00946 if (0 == safe_strcmp (object_name, params->qof_foreach)) 00947 { 00948 params->foreach_limit++; 00949 } 00950 } 00951 } 00952 00953 xmlDocPtr 00954 qsf_object_convert (xmlDocPtr mapDoc, xmlNodePtr qsf_root, 00955 QsfParam * params) 00956 { 00957 /* mapDoc : map document. qsf_root: incoming QSF root node. */ 00958 struct QsfNodeIterate qsfiter; 00959 xmlDocPtr output_doc; 00960 xmlNode *cur_node; 00961 xmlNode *map_root, *output_root; 00962 00963 g_return_val_if_fail ((mapDoc && qsf_root && params), NULL); 00964 ENTER (" root=%s", qsf_root->name); 00965 /* prepare the intermediary document */ 00966 qsfiter.ns = params->qsf_ns; 00967 output_doc = xmlNewDoc (BAD_CAST QSF_XML_VERSION); 00968 output_root = xmlNewNode (NULL, BAD_CAST QSF_ROOT_TAG); 00969 xmlDocSetRootElement (output_doc, output_root); 00970 xmlSetNs (output_root, params->qsf_ns); 00971 params->output_node = xmlNewChild (output_root, params->qsf_ns, 00972 BAD_CAST QSF_BOOK_TAG, NULL); 00973 xmlNewProp (params->output_node, BAD_CAST QSF_BOOK_COUNT, 00974 BAD_CAST "1"); 00975 /* parse the incoming QSF */ 00976 qsf_book_node_handler (qsf_root->children->next, params->qsf_ns, 00977 params); 00978 /* parse the map and calculate the values */ 00979 map_root = xmlDocGetRootElement (mapDoc); 00980 params->foreach_limit = 0; 00981 qsfiter.ns = params->map_ns; 00982 /* sets qof_foreach iterator, defines and defaults. */ 00983 qsf_node_foreach (map_root, qsf_map_top_node_handler, &qsfiter, params); 00984 /* identify the entities of iterator type. */ 00985 qsfiter.ns = params->qsf_ns; 00986 qsf_node_foreach (qsf_root->children->next, iterator_cb, &qsfiter, 00987 params); 00988 PINFO (" counted %d records", params->foreach_limit); 00989 params->count = 0; 00990 for (cur_node = map_root->children; cur_node != NULL; 00991 cur_node = cur_node->next) 00992 { 00993 params->convert_node = cur_node; 00994 if (qsf_is_element (cur_node, params->map_ns, MAP_OBJECT_TAG)) 00995 { 00996 gint i; 00997 00998 params->lister = NULL; 00999 PINFO (" found an object tag. starting calculation"); 01000 /* cur_node describes the target object */ 01001 if (!qof_class_is_registered (BAD_CAST 01002 xmlGetProp (cur_node, MAP_TYPE_ATTR))) 01003 { 01004 continue; 01005 } 01006 qsf_add_object_tag (params, params->count); 01007 params->count++; 01008 qsfiter.ns = params->map_ns; 01009 PINFO (" params->foreach_limit=%d", params->foreach_limit); 01010 for (i = -1; i < params->foreach_limit; i++) 01011 { 01012 qsf_node_foreach (cur_node, qsf_map_object_handler, 01013 &qsfiter, params); 01014 params->qsf_object_list = 01015 g_list_next (params->qsf_object_list); 01016 params->count++; 01017 } 01018 } 01019 } 01020 params->file_type = OUR_QSF_OBJ; 01021 /* use for debugging */ 01022 xmlSaveFormatFileEnc ("-", output_doc, "UTF-8", 1); 01023 LEAVE (" "); 01024 return output_doc; 01025 }