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