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