qsf-xml-map.c

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

Generated on Fri May 12 17:57:21 2006 for QOF by  doxygen 1.4.4