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

Generated on Thu Jan 31 22:50:26 2008 for QOF by  doxygen 1.5.4