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 #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     qsf_validator * 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 = ERR_QSF_BAD_QOF_VERSION;
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 = ERR_QSF_WRONG_MAP;
00176         }
00177     }
00178 }
00179 
00180 static QofBackendError
00181 check_qsf_object_with_map_internal (xmlDocPtr map_doc, xmlDocPtr doc)
00182 {
00183     xmlNodePtr map_root, object_root;
00184     struct qsf_node_iterate iter;
00185     qsf_validator 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 = ERR_BACKEND_NO_ERR;
00197     map_ns = map_root->ns;
00198     iter.ns = object_root->ns;
00199     qsf_valid_foreach (object_root, qsf_object_validation_handler, &iter,
00200         &valid);
00201     iter.ns = map_ns;
00202     qsf_valid_foreach (map_root, qsf_map_validation_handler, &iter,
00203         &valid);
00204     if (valid.error_state != ERR_BACKEND_NO_ERR)
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         if (valid.error_state != ERR_BACKEND_NO_ERR)
00231         {
00232             valid.error_state = ERR_QSF_WRONG_MAP;
00233         }
00234         g_hash_table_destroy (valid.object_table);
00235         g_hash_table_destroy (valid.map_table);
00236         return valid.error_state;
00237     }
00238     g_hash_table_destroy (valid.object_table);
00239     g_hash_table_destroy (valid.map_table);
00240     return ERR_BACKEND_NO_ERR;
00241 }
00242 
00243 gboolean
00244 is_qsf_object_with_map_be (gchar * map_file, qsf_param * params)
00245 {
00246     xmlDocPtr doc, map_doc;
00247     QofBackendError result;
00248     gchar *path, *map_path;
00249 
00250     g_return_val_if_fail ((params != NULL), FALSE);
00251     path = g_strdup (params->filepath);
00252     map_path = g_strdup_printf ("%s/%s", QSF_SCHEMA_DIR, map_file);
00253     PINFO (" checking map file '%s'", map_path);
00254     if (path == NULL)
00255     {
00256         qof_backend_set_error (params->be, ERR_FILEIO_FILE_NOT_FOUND);
00257         return FALSE;
00258     }
00259     doc = xmlParseFile (path);
00260     if (doc == NULL)
00261     {
00262         qof_backend_set_error (params->be, ERR_FILEIO_PARSE_ERROR);
00263         return FALSE;
00264     }
00265     if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
00266     {
00267         qof_backend_set_error (params->be, ERR_QSF_INVALID_OBJ);
00268         return FALSE;
00269     }
00270     if (map_path == NULL)
00271     {
00272         qof_backend_set_error (params->be, ERR_FILEIO_FILE_NOT_FOUND);
00273         return FALSE;
00274     }
00275     map_doc = xmlParseFile (map_path);
00276     if (map_doc == NULL)
00277     {
00278         qof_backend_set_error (params->be, ERR_FILEIO_PARSE_ERROR);
00279         return FALSE;
00280     }
00281     result = check_qsf_object_with_map_internal (map_doc, doc);
00282     qof_backend_set_error (params->be, result);
00283     return (result == ERR_BACKEND_NO_ERR) ? TRUE : FALSE;
00284 }
00285 
00286 gboolean
00287 is_qsf_object_with_map (const gchar * path, gchar * map_file)
00288 {
00289     xmlDocPtr doc, map_doc;
00290     QofBackendError result;
00291     gchar *map_path;
00292 
00293     map_path = g_strdup_printf ("%s/%s", QSF_SCHEMA_DIR, map_file);
00294     if (path == NULL)
00295     {
00296         return FALSE;
00297     }
00298     doc = xmlParseFile (path);
00299     if (doc == NULL)
00300     {
00301         return FALSE;
00302     }
00303     if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
00304     {
00305         return FALSE;
00306     }
00307     if (map_path == NULL)
00308     {
00309         return FALSE;
00310     }
00311     map_doc = xmlParseFile (map_path);
00312     result = check_qsf_object_with_map_internal (map_doc, doc);
00313     return (result == ERR_BACKEND_NO_ERR) ? TRUE : FALSE;
00314 }
00315 
00316 gboolean
00317 is_qsf_map_be (qsf_param * params)
00318 {
00319     xmlDocPtr doc;
00320     struct qsf_node_iterate iter;
00321     qsf_validator valid;
00322     xmlNodePtr map_root;
00323     xmlNsPtr map_ns;
00324     gchar *path;
00325 
00326     g_return_val_if_fail ((params != NULL), FALSE);
00327     qof_backend_get_error (params->be);
00328     path = g_strdup (params->filepath);
00329     if (path == NULL)
00330     {
00331         qof_backend_set_error (params->be, ERR_FILEIO_FILE_NOT_FOUND);
00332         return FALSE;
00333     }
00334     doc = xmlParseFile (path);
00335     if (doc == NULL)
00336     {
00337         qof_backend_set_error (params->be, ERR_FILEIO_PARSE_ERROR);
00338         return FALSE;
00339     }
00340     if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_MAP_SCHEMA, doc))
00341     {
00342         qof_backend_set_error (params->be, ERR_QSF_INVALID_MAP);
00343         return FALSE;
00344     }
00345     map_root = xmlDocGetRootElement (doc);
00346     map_ns = map_root->ns;
00347     iter.ns = map_ns;
00348     valid.object_table = g_hash_table_new (g_str_hash, g_str_equal);
00349     valid.map_table = g_hash_table_new (g_str_hash, g_str_equal);
00350     valid.error_state = ERR_BACKEND_NO_ERR;
00351     qsf_valid_foreach (map_root, qsf_map_validation_handler, &iter,
00352         &valid);
00353     if (valid.error_state != ERR_BACKEND_NO_ERR)
00354     {
00355         qof_backend_set_error (params->be, valid.error_state);
00356         g_hash_table_destroy (valid.object_table);
00357         return FALSE;
00358     }
00359     qof_backend_get_error (params->be);
00360     g_hash_table_destroy (valid.object_table);
00361     return TRUE;
00362 }
00363 
00364 gboolean
00365 is_qsf_map (const gchar * path)
00366 {
00367     xmlDocPtr doc;
00368     struct qsf_node_iterate iter;
00369     qsf_validator valid;
00370     xmlNodePtr map_root;
00371     xmlNsPtr map_ns;
00372 
00373     g_return_val_if_fail ((path != NULL), FALSE);
00374     if (path == NULL)
00375     {
00376         return FALSE;
00377     }
00378     doc = xmlParseFile (path);
00379     if (doc == NULL)
00380     {
00381         return FALSE;
00382     }
00383     if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_MAP_SCHEMA, doc))
00384     {
00385         return FALSE;
00386     }
00387     map_root = xmlDocGetRootElement (doc);
00388     map_ns = map_root->ns;
00389     iter.ns = map_ns;
00390     valid.error_state = ERR_BACKEND_NO_ERR;
00391     valid.map_table = g_hash_table_new (g_str_hash, g_str_equal);
00392     qsf_valid_foreach (map_root, qsf_map_validation_handler, &iter,
00393         &valid);
00394     if (valid.error_state != ERR_BACKEND_NO_ERR)
00395     {
00396         g_hash_table_destroy (valid.map_table);
00397         return FALSE;
00398     }
00399     g_hash_table_destroy (valid.map_table);
00400     return TRUE;
00401 }
00402 
00403 static void
00404 qsf_map_default_handler (xmlNodePtr child, xmlNsPtr ns, qsf_param * params)
00405 {
00406     xmlChar *qsf_enum;
00407     gchar *iterate;
00408 
00409     g_return_if_fail (params->qsf_define_hash != NULL);
00410     iterate = NULL;
00411     if (qsf_is_element (child, ns, MAP_DEFINE_TAG))
00412     {
00413         iterate = xmlGetProp (child, MAP_ITERATE_ATTR);
00414         if ((qof_util_bool_to_int (iterate) == 1) &&
00415             (qof_class_is_registered
00416                 (xmlGetProp (child, BAD_CAST MAP_E_TYPE))))
00417         {
00418             params->qof_foreach = xmlGetProp (child, BAD_CAST MAP_E_TYPE);
00419             PINFO (" iterating over '%s' objects", params->qof_foreach);
00420         }
00421         if (NULL == g_hash_table_lookup (params->qsf_define_hash,
00422                 xmlGetProp (child, BAD_CAST MAP_E_TYPE)))
00423         {
00424             g_hash_table_insert (params->qsf_define_hash,
00425                 xmlGetProp (child, BAD_CAST MAP_E_TYPE),
00426                 params->child_node);
00427         }
00428         else
00429         {
00430             qof_backend_set_error (params->be, ERR_QSF_BAD_MAP);
00431             PERR (" ERR_QSF_BAD_MAP set");
00432             return;
00433         }
00434     }
00435     if (qsf_is_element (child, ns, MAP_DEFAULT_TAG))
00436     {
00437         if (qsf_strings_equal
00438             (xmlGetProp (child, BAD_CAST MAP_TYPE_ATTR), MAP_ENUM_TYPE))
00439         {
00440             qsf_enum = xmlNodeGetContent (child);
00442             PERR (" enum todo incomplete");
00446             if (NULL == g_hash_table_lookup (params->qsf_default_hash,
00447                     xmlNodeGetContent (child)))
00448             {
00449                 g_hash_table_insert (params->qsf_default_hash,
00450                     xmlNodeGetContent (child), child);
00451             }
00452             else
00453             {
00454                 qof_backend_set_error (params->be, ERR_QSF_BAD_MAP);
00455                 PERR (" ERR_QSF_BAD_MAP set");
00456                 return;
00457             }
00458         }
00460         else
00461         {
00462             if (NULL == g_hash_table_lookup (params->qsf_default_hash,
00463                     xmlGetProp (child, BAD_CAST MAP_NAME_ATTR)))
00464             {
00465                 g_hash_table_insert (params->qsf_default_hash,
00466                     xmlGetProp (child, BAD_CAST MAP_NAME_ATTR), child);
00467             }
00468             else
00469 /*                  if(0 != xmlHashAddEntry(params->default_map,
00470                 xmlGetProp(child_node, MAP_NAME_ATTR), child_node))*/
00471             {
00472                 qof_backend_set_error (params->be, ERR_QSF_BAD_MAP);
00473                 PERR (" ERR_QSF_BAD_MAP set");
00474                 return;
00475             }
00476         }
00477     }
00478 }
00479 
00480 static void
00481 qsf_map_top_node_handler (xmlNodePtr child, xmlNsPtr ns,
00482     qsf_param * params)
00483 {
00484     xmlChar *qof_version;
00485     gchar *buff;
00486     struct qsf_node_iterate iter;
00487 
00488     if (!params->qsf_define_hash)
00489         return;
00490     if (!params->qsf_default_hash)
00491         return;
00492     ENTER (" map top node child=%s", child->name);
00493     buff = NULL;
00494     if (qsf_is_element (child, ns, MAP_DEFINITION_TAG))
00495     {
00496         qof_version = xmlGetProp (child, BAD_CAST MAP_QOF_VERSION);
00497         buff = g_strdup_printf ("%i", QSF_QOF_VERSION);
00498         if (xmlStrcmp (qof_version, BAD_CAST buff) != 0)
00499         {
00500             qof_backend_set_error (params->be, ERR_QSF_BAD_QOF_VERSION);
00501             LEAVE (" ERR_QSF_BAD_QOF_VERSION set");
00502             return;
00503         }
00504         iter.ns = ns;
00505         qsf_node_foreach (child, qsf_map_default_handler, &iter, params);
00506     }
00507     LEAVE (" ");
00508 }
00509 
00510 static char *
00511 qsf_else_set_value (xmlNodePtr parent, GHashTable * default_hash,
00512     gchar * content, xmlNsPtr map_ns)
00513 {
00514     xmlNodePtr cur_node;
00515 
00516     content = NULL;
00517     for (cur_node = parent->children; cur_node != NULL;
00518         cur_node = cur_node->next)
00519     {
00520         if (qsf_is_element (cur_node, map_ns, QSF_CONDITIONAL_SET))
00521         {
00522             content = (gchar *) xmlNodeGetContent (cur_node);
00523             return content;
00524         }
00525     }
00526     return NULL;
00527 }
00528 
00529 /* Handles the set tag in the map.
00530 This function will be overhauled once inside QOF
00531 QOF hook required for "Lookup in the receiving application"
00532 */
00533 static gchar *
00534 qsf_set_handler (xmlNodePtr parent, GHashTable * default_hash,
00535     gchar * content, qsf_param * params)
00536 {
00537     xmlNodePtr cur_node, lookup_node;
00538 
00539     ENTER (" lookup problem");
00540     content = NULL;
00541     for (cur_node = parent->children; cur_node != NULL;
00542         cur_node = cur_node->next)
00543     {
00544         if (qsf_is_element (cur_node, params->map_ns, QSF_CONDITIONAL_SET))
00545         {
00546             content = (gchar *) xmlGetProp (cur_node, BAD_CAST QSF_OPTION);
00547             if (qsf_strings_equal (xmlGetProp (cur_node,
00548                         BAD_CAST QSF_OPTION), "qsf_lookup_string"))
00549             {
00550                 lookup_node =
00551                     (xmlNodePtr) g_hash_table_lookup (default_hash,
00552                     xmlNodeGetContent (cur_node));
00553                 content =
00554                     (gchar *) xmlGetProp (lookup_node,
00555                     BAD_CAST MAP_VALUE_ATTR);
00557                 /* Find by name, get GUID, return GUID as string. */
00558                 g_message ("Lookup %s in the receiving application\n",
00559                     content);
00560                 LEAVE (" todo");
00561                 return content;
00562             }
00563             if (content)
00564             {
00565                 lookup_node =
00566                     (xmlNodePtr) g_hash_table_lookup (default_hash,
00567                     xmlNodeGetContent (cur_node));
00568                 content =
00569                     (gchar *) xmlGetProp (lookup_node, BAD_CAST "value");
00570                 return content;
00571             }
00572             content = (gchar *) xmlGetProp (parent, BAD_CAST "boolean");
00573             if (!content)
00574             {
00576                 lookup_node =
00577                     (xmlNodePtr) g_hash_table_lookup (params->
00578                     qsf_parameter_hash,
00579                     xmlGetProp (parent->parent, BAD_CAST MAP_TYPE_ATTR));
00580                 if (lookup_node)
00581                 {
00582                     return (gchar *) xmlNodeGetContent (lookup_node);
00583                 }
00584                 LEAVE (" check arguments");
00585                 return (gchar *) xmlNodeGetContent (cur_node);
00586             }
00587         }
00588     }
00589     LEAVE (" null");
00590     return NULL;
00591 }
00592 
00593 static void
00594 qsf_calculate_else (xmlNodePtr param_node, xmlNodePtr child,
00595     qsf_param * params)
00596 {
00597     xmlNodePtr export_node;
00598     xmlChar *output_content, *object_data;
00599 
00600     if (qsf_is_element (param_node, params->map_ns, QSF_CONDITIONAL_ELSE))
00601     {
00602         if (params->boolean_calculation_done == 0)
00603         {
00604             output_content = object_data = NULL;
00605             output_content = BAD_CAST qsf_set_handler (param_node,
00606                 params->
00607                 qsf_default_hash, (gchar *) output_content, params);
00608             if (output_content == NULL)
00609             {
00610                 output_content =
00611                     xmlGetProp (param_node, BAD_CAST MAP_TYPE_ATTR);
00612                 object_data =
00613                     BAD_CAST qsf_else_set_value (param_node,
00614                     params->qsf_default_hash,
00615                     (gchar *) output_content, params->map_ns);
00616                 output_content =
00617                     BAD_CAST xmlGetProp ((xmlNodePtr)
00618                     g_hash_table_lookup (params->
00619                         qsf_default_hash,
00620                         object_data), BAD_CAST MAP_VALUE_ATTR);
00621             }
00622             if (object_data != NULL)
00623             {
00624                 export_node =
00625                     (xmlNodePtr) g_hash_table_lookup (params->
00626                     qsf_parameter_hash,
00627                     xmlGetProp (params->
00628                         child_node, BAD_CAST QSF_OBJECT_TYPE));
00629                 object_data = xmlNodeGetContent (export_node);
00630             }
00631             if (output_content != NULL)
00632             {
00633                 object_data = output_content;
00634             }
00635             export_node =
00636                 xmlAddChild (params->lister,
00637                 xmlNewNode (params->qsf_ns,
00638                     xmlGetProp (child, BAD_CAST QSF_OBJECT_TYPE)));
00639             xmlNewProp (export_node, BAD_CAST QSF_OBJECT_TYPE,
00640                 xmlGetProp (child, BAD_CAST MAP_VALUE_ATTR));
00641             xmlNodeAddContent (export_node, object_data);
00642             params->boolean_calculation_done = 1;
00643         }
00644     }
00645 }
00646 
00647 static void
00648 qsf_set_format_value (xmlChar * format, gchar * qsf_time_now_as_string,
00649     xmlNodePtr cur_node, qsf_param * params)
00650 {
00651     gint result;
00652     xmlChar *content;
00653     time_t *output;
00654     struct tm *tmp;
00655     time_t tester;
00656     xmlNodePtr kl;
00657     regex_t reg;
00658 
00661     result = 0;
00662     if (format == NULL)
00663     {
00664         return;
00665     }
00666     ENTER (" ");
00667     content = xmlNodeGetContent (cur_node);
00668     output =
00669         (time_t *) g_hash_table_lookup (params->qsf_default_hash, content);
00670     if (!output)
00671     {
00674         tester = time (NULL);
00675         tmp = gmtime (&tester);
00678         kl = (xmlNodePtr) g_hash_table_lookup (params->qsf_parameter_hash,
00679             content);
00680         if (!kl)
00681         {
00682             LEAVE (" no suitable date set.");
00683             return;
00684         }
00686         strptime ((char *) xmlNodeGetContent (kl), QSF_XSD_TIME, tmp);
00687         if (!tmp)
00688         {
00689             LEAVE (" empty date field in QSF object.\n");
00690             return;
00691         }
00692         tester = mktime (tmp);
00693         output = &tester;
00694     }
00695     result = regcomp (&reg, "%[a-zA-Z]", REG_EXTENDED | REG_NOSUB);
00696     result = regexec (&reg, (gchar *) format, (size_t) 0, NULL, 0);
00697     if (result == REG_NOMATCH)
00698     {
00699         format = BAD_CAST "%F";
00700     }
00701     regfree (&reg);
00702     /* QSF_DATE_LENGTH preset for all internal and QSF_XSD_TIME string formats. */
00703     strftime (qsf_time_now_as_string, QSF_DATE_LENGTH, (char *) format,
00704         gmtime (output));
00705     LEAVE (" ok");
00706 }
00707 
00708 static void
00709 qsf_boolean_set_value (xmlNodePtr parent, qsf_param * params,
00710     gchar * content, xmlNsPtr map_ns)
00711 {
00712     xmlNodePtr cur_node;
00713     xmlChar *boolean_name;
00714 
00715     boolean_name = NULL;
00716     for (cur_node = parent->children; cur_node != NULL;
00717         cur_node = cur_node->next)
00718     {
00719         if (qsf_is_element (cur_node, map_ns, QSF_CONDITIONAL_SET))
00720         {
00721             boolean_name =
00722                 xmlGetProp (cur_node, BAD_CAST QSF_FORMATTING_OPTION);
00723             qsf_set_format_value (boolean_name, content, cur_node, params);
00724         }
00725     }
00726 }
00727 
00728 static void
00729 qsf_calculate_conditional (xmlNodePtr param_node, xmlNodePtr child,
00730     qsf_param * params)
00731 {
00732     xmlNodePtr export_node;
00733     xmlChar *output_content;
00734 
00735     output_content = NULL;
00736     if (qsf_is_element (param_node, params->map_ns, QSF_CONDITIONAL))
00737     {
00738         if (params->boolean_calculation_done == 0)
00739         {
00740             /* set handler */
00741             output_content =
00742                 BAD_CAST qsf_set_handler (param_node,
00743                 params->qsf_default_hash,
00744                 (gchar *) output_content, params);
00745             /* If the 'if' contains a boolean that has a default value */
00746             if (output_content == NULL)
00747             {
00748                 if (NULL !=
00749                     xmlGetProp (param_node, BAD_CAST QSF_BOOLEAN_DEFAULT))
00750                 {
00751                     output_content =
00752                         xmlGetProp ((xmlNodePtr)
00753                         g_hash_table_lookup (params->
00754                             qsf_default_hash,
00755                             xmlGetProp
00756                             (param_node,
00757                                 BAD_CAST
00758                                 QSF_BOOLEAN_DEFAULT)),
00759                         BAD_CAST MAP_VALUE_ATTR);
00760                 }
00761                 /* Is the default set to true? */
00762                 if (0 ==
00763                     qsf_compare_tag_strings (output_content,
00764                         QSF_XML_BOOLEAN_TEST))
00765                 {
00766                     qsf_boolean_set_value (param_node, params,
00767                         (gchar *) output_content, params->map_ns);
00768                     export_node =
00769                         xmlAddChild (params->lister,
00770                         xmlNewNode (params->qsf_ns,
00771                             xmlGetProp (child, BAD_CAST QSF_OBJECT_TYPE)));
00772                     xmlNewProp (export_node, BAD_CAST QSF_OBJECT_TYPE,
00773                         xmlGetProp (child, BAD_CAST MAP_VALUE_ATTR));
00774                     xmlNodeAddContent (export_node, output_content);
00775                     params->boolean_calculation_done = 1;
00776                 }
00777             }
00778         }
00779     }
00780 }
00781 
00782 static void
00783 qsf_add_object_tag (qsf_param * params, gint count)
00784 {
00785     xmlNodePtr extra_node;
00786     GString *str;
00787     xmlChar *property;
00788 
00789     str = g_string_new (" ");
00790     g_string_printf (str, "%i", count);
00791     extra_node = NULL;
00792     extra_node = xmlAddChild (params->output_node,
00793         xmlNewNode (params->qsf_ns, BAD_CAST QSF_OBJECT_TAG));
00794     xmlNewProp (extra_node, BAD_CAST QSF_OBJECT_TYPE,
00795         xmlGetProp (params->convert_node, BAD_CAST QSF_OBJECT_TYPE));
00796     property = xmlCharStrdup (str->str);
00797     xmlNewProp (extra_node, BAD_CAST QSF_OBJECT_COUNT, property);
00798     params->lister = extra_node;
00799 }
00800 
00801 static gint
00802 identify_source_func (gconstpointer qsf_object, gconstpointer map)
00803 {
00804     PINFO (" qsf_object=%s, map=%s",
00805         ((qsf_objects *) qsf_object)->object_type, (QofIdType) map);
00806     return safe_strcmp (((qsf_objects *) qsf_object)->object_type,
00807         (QofIdType) map);
00808 }
00809 
00810 static void
00811 qsf_map_calculate_output (xmlNodePtr param_node, xmlNodePtr child,
00812     qsf_param * params)
00813 {
00814     xmlNodePtr export_node;
00815     xmlChar *output_content;
00816     xmlNodePtr input_node;
00817     GList *source;
00818 
00819     output_content = xmlNodeGetContent (param_node);
00820     DEBUG (" %s", output_content);
00821     /* source refers to the source object that provides the data */
00822     source = g_list_find_custom (params->qsf_object_list,
00823         BAD_CAST xmlGetProp (param_node,
00824             MAP_OBJECT_ATTR), identify_source_func);
00825     PINFO (" checking %s", BAD_CAST xmlGetProp (param_node,
00826             MAP_OBJECT_ATTR));
00827     if (!source)
00828     {
00829         DEBUG (" no source found in list.");
00830         return;
00831     }
00832     params->object_set = source->data;
00833     input_node = g_hash_table_lookup (params->object_set->parameters,
00834         output_content);
00835     DEBUG (" node_value=%s, content=%s",
00836         xmlGetProp (child, BAD_CAST MAP_VALUE_ATTR),
00837         xmlNodeGetContent (input_node));
00838     export_node = xmlAddChild (params->lister, xmlNewNode (params->qsf_ns,
00839             xmlGetProp (child, BAD_CAST QSF_OBJECT_TYPE)));
00840     xmlNewProp (export_node, BAD_CAST QSF_OBJECT_TYPE,
00841         xmlGetProp (child, BAD_CAST MAP_VALUE_ATTR));
00842     xmlNodeAddContent (export_node, xmlNodeGetContent (input_node));
00843 }
00844 
00845 static void
00846 qsf_map_object_handler (xmlNodePtr child, xmlNsPtr ns, qsf_param * params)
00847 {
00848     xmlNodePtr param_node;
00849     xmlNsPtr map_ns, qsf_ns;
00850     gint result;
00851 
00852     map_ns = ns;
00853     qsf_ns = params->qsf_ns;
00854     param_node = NULL;
00855     result = 0;
00856     if (child == NULL)
00857     {
00858         return;
00859     }
00860     if (ns == NULL)
00861     {
00862         return;
00863     }
00864     params->boolean_calculation_done = 0;
00865 
00866     if (qsf_is_element (child, map_ns, MAP_CALCULATE_TAG))
00867     {
00868         params->boolean_calculation_done = 0;
00869         /* read the child nodes to prepare the calculation. */
00870         for (param_node = child->children; param_node != NULL;
00871             param_node = param_node->next)
00872         {
00873             if (qsf_is_element (param_node, map_ns, QSF_CONDITIONAL_SET))
00874             {
00875                 /* Map the pre-defined defaults */
00876                 if (0 ==
00877                     qsf_compare_tag_strings (xmlNodeGetContent
00878                         (param_node), "qsf_enquiry_date"))
00879                 {
00880                     qsf_string_default_handler ("qsf_enquiry_date",
00881                         params->qsf_default_hash,
00882                         params->lister, child, qsf_ns);
00883                 }
00884                 if (0 ==
00885                     qsf_compare_tag_strings (xmlNodeGetContent
00886                         (param_node), "qsf_time_now"))
00887                 {
00888                     qsf_date_default_handler ("qsf_time_now",
00889                         params->qsf_default_hash,
00890                         params->lister, child, qsf_ns);
00891                 }
00892                 if (0 ==
00893                     qsf_compare_tag_strings (xmlNodeGetContent
00894                         (param_node), "qsf_time_string"))
00895                 {
00896                     qsf_string_default_handler ("qsf_time_string",
00897                         params->qsf_default_hash,
00898                         params->lister, child, qsf_ns);
00899                 }
00900                 qsf_map_calculate_output (param_node, child, params);
00901             }
00902             qsf_calculate_conditional (param_node, child, params);
00903             qsf_calculate_else (param_node, child, params);
00904         }
00905         /* calculate_map currently not in use */
00906         /* ensure uniqueness of the key before re-instating */
00907 /*      result = xmlHashAddEntry2(calculate_map,
00908             xmlGetProp(child_node, MAP_TYPE_ATTR),
00909             xmlGetProp(child_node, MAP_VALUE_ATTR), child_node);
00910         if(result != 0) {
00911             printf("add entry to calculate hash failed. %s\t%s\t%s.\n",
00912                 xmlGetProp(child_node, MAP_TYPE_ATTR),
00913             xmlGetProp(child_node, MAP_VALUE_ATTR), child_node->name);
00914             return;
00915         }
00916 
00917         is_qsf_object_with_map(path, map_path);
00918 */
00919     }
00920 }
00921 
00922 static void
00923 iterator_cb (xmlNodePtr child, xmlNsPtr ns, qsf_param * params)
00924 {
00925     gchar *object_name;
00926 
00927     /* count the number of iterators in the QSF file */
00928     if (qsf_is_element (child, ns, QSF_OBJECT_TAG))
00929     {
00930         object_name = xmlGetProp (child, QSF_OBJECT_TYPE);
00931         if (0 == safe_strcmp (object_name, params->qof_foreach))
00932         {
00933             params->foreach_limit++;
00934         }
00935     }
00936 }
00937 
00938 xmlDocPtr
00939 qsf_object_convert (xmlDocPtr mapDoc, xmlNodePtr qsf_root,
00940     qsf_param * params)
00941 {
00942     /* mapDoc : map document. qsf_root: incoming QSF root node. */
00943     struct qsf_node_iterate iter;
00944     xmlDocPtr output_doc;
00945     xmlNode *cur_node;
00946     xmlNode *map_root, *output_root;
00947 
00948     g_return_val_if_fail ((mapDoc && qsf_root && params), NULL);
00949     ENTER (" root=%s", qsf_root->name);
00950     /* prepare the intermediary document */
00951     iter.ns = params->qsf_ns;
00952     output_doc = xmlNewDoc (BAD_CAST QSF_XML_VERSION);
00953     output_root = xmlNewNode (NULL, BAD_CAST QSF_ROOT_TAG);
00954     xmlDocSetRootElement (output_doc, output_root);
00955     xmlSetNs (output_root, params->qsf_ns);
00956     params->output_node = xmlNewChild (output_root, params->qsf_ns,
00957         BAD_CAST QSF_BOOK_TAG, NULL);
00958     xmlNewProp (params->output_node, BAD_CAST QSF_BOOK_COUNT,
00959         BAD_CAST "1");
00960     /* parse the incoming QSF */
00961     qsf_book_node_handler (qsf_root->children->next, params->qsf_ns,
00962         params);
00963     /* parse the map and calculate the values */
00964     map_root = xmlDocGetRootElement (mapDoc);
00965     params->foreach_limit = 0;
00966     iter.ns = params->map_ns;
00967     /* sets qof_foreach iterator, defines and defaults. */
00968     qsf_node_foreach (map_root, qsf_map_top_node_handler, &iter, params);
00969     /* identify the entities of iterator type. */
00970     iter.ns = params->qsf_ns;
00971     qsf_node_foreach (qsf_root->children->next, iterator_cb, &iter,
00972         params);
00973     PINFO (" counted %d records", params->foreach_limit);
00974     params->count = 0;
00975     for (cur_node = map_root->children; cur_node != NULL;
00976         cur_node = cur_node->next)
00977     {
00978         params->convert_node = cur_node;
00979         if (qsf_is_element (cur_node, params->map_ns, MAP_OBJECT_TAG))
00980         {
00981             gint i;
00982 
00983             params->lister = NULL;
00984             PINFO (" found an object tag. starting calculation");
00985             /* cur_node describes the target object */
00986             if (!qof_class_is_registered (BAD_CAST
00987                     xmlGetProp (cur_node, MAP_TYPE_ATTR)))
00988             {
00989                 continue;
00990             }
00991             qsf_add_object_tag (params, params->count);
00992             params->count++;
00993             iter.ns = params->map_ns;
00994             PINFO (" params->foreach_limit=%d", params->foreach_limit);
00995             for (i = -1; i < params->foreach_limit; i++)
00996             {
00997                 qsf_node_foreach (cur_node, qsf_map_object_handler, &iter,
00998                     params);
00999                 params->qsf_object_list =
01000                     g_list_next (params->qsf_object_list);
01001                 params->count++;
01002             }
01003         }
01004     }
01005     params->file_type = OUR_QSF_OBJ;
01006     /* use for debugging */
01007     xmlSaveFormatFileEnc ("-", output_doc, "UTF-8", 1);
01008     LEAVE (" ");
01009     return output_doc;
01010 }

Generated on Fri Sep 1 15:09:03 2006 for QOF by  doxygen 1.4.7