QOF 0.8.2

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 
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 (&reg, "%[a-zA-Z]", REG_EXTENDED | REG_NOSUB);
00710     result = regexec (&reg, (gchar *) format, (size_t) 0, NULL, 0);
00711     if (result == REG_NOMATCH)
00712     {
00713         format = BAD_CAST "%F";
00714     }
00715     regfree (&reg);
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 }