Definition in file qsf-xml.h.
#include <stdio.h>
#include <stdlib.h>
#include <regex.h>
#include <time.h>
#include "qof.h"
#include <libintl.h>
Go to the source code of this file.
Data Structures | |
struct | qsf_object_set |
Holds a description of the QofObject. More... | |
struct | qsf_metadata |
QSF Parameters. More... | |
struct | qsf_validates |
Validation metadata. More... | |
struct | qsf_node_iterate |
One iterator, two typedefs. More... | |
Why two sets of functions and typedefs? | |
These functions are in pairs, one to use in an existing session and one to use when deciding which backend should be selected for a new session.
| |
typedef void(*) | qsf_nodeCB (xmlNodePtr, xmlNsPtr, qsf_param *) |
map and qsf object callback | |
typedef void(*) | qsf_validCB (xmlNodePtr, xmlNsPtr, qsf_validator *) |
validator callback | |
gboolean | is_qsf_object_be (qsf_param *params) |
Validate a QSF file and identify a suitable QSF map. | |
gboolean | is_qsf_object (const gchar *path) |
Validate a QSF file and identify a suitable QSF map. | |
gboolean | is_our_qsf_object_be (qsf_param *params) |
Validate a QSF file and determine type. | |
gboolean | is_our_qsf_object (const gchar *path) |
Validate a QSF file. | |
gboolean | is_qsf_map_be (qsf_param *params) |
Validate a QSF map file. | |
gboolean | is_qsf_map (const gchar *path) |
Validate a QSF map file. | |
gboolean | is_qsf_object_with_map_be (gchar *map_path, qsf_param *params) |
Validate a QSF file and a selected QSF map. | |
gboolean | is_qsf_object_with_map (const gchar *path, gchar *map_file) |
Validate a QSF file and a selected QSF map. | |
Defines | |
#define | _(String) dgettext (GETTEXT_PACKAGE, String) |
#define | QSF_QOF_VERSION QOF_OBJECT_VERSION |
#define | QSF_XSD_TIME QOF_UTC_DATE_FORMAT |
#define | QSF_XML_BOOLEAN_TEST "true" |
#define | QSF_OBJECT_SCHEMA "qsf-object.xsd.xml" |
#define | QSF_MAP_SCHEMA "qsf-map.xsd.xml" |
QSF Object XML | |
#define | QSF_ROOT_TAG "qof-qsf" |
#define | QSF_DEFAULT_NS "http://qof.sourceforge.net/" |
#define | QSF_DATE_LENGTH MAX_DATE_LENGTH |
#define | QSF_BOOK_TAG "book" |
#define | QSF_BOOK_GUID "book-guid" |
#define | QSF_BOOK_COUNT "count" |
#define | QSF_OBJECT_TAG "object" |
#define | QSF_OBJECT_TYPE "type" |
#define | QSF_OBJECT_COUNT "count" |
#define | QSF_XML_VERSION "1.0" |
Representing KVP as XML | |
<kvp type="kvp" path="/from-sched-xaction" value="guid">c858b9a3235723b55bc1179f0e8c1322</kvp> A kvp type KVP parameter located at $path containing a GUID $value. The relevance of type="kvp" won't be evident in GnuCash, they all use "kvp".
A non-GnuCash example helps: <kvp type="pilot_addr_kvp" path="/user/name" value="guid">c858b9a3235723b55bc1179f0e8c1322</kvp> A pilot_addr_kvp type KVP parameter located at /user/name containing a guid value. | |
#define | QSF_OBJECT_KVP "path" |
#define | QSF_OBJECT_VALUE "value" |
QSF Map XML | |
#define | MAP_ROOT_TAG "qsf-map" |
#define | MAP_DEFINITION_TAG "definition" |
#define | MAP_DEFINE_TAG "define" |
#define | MAP_ITERATE_ATTR "foreach" |
#define | MAP_DEFAULT_TAG "default" |
#define | MAP_OBJECT_TAG "object" |
#define | MAP_CALCULATE_TAG "calculate" |
#define | MAP_QOF_VERSION "qof_version" |
#define | MAP_NAME_ATTR "name" |
#define | MAP_TYPE_ATTR "type" |
#define | MAP_VALUE_ATTR "value" |
#define | MAP_OBJECT_ATTR "object" |
#define | MAP_E_TYPE "e_type" |
#define | MAP_ENUM_TYPE "enum" |
#define | QSF_BOOLEAN_DEFAULT "boolean" |
A specific boolean default for this map. | |
#define | QSF_CONDITIONAL "if" |
#define | QSF_CONDITIONAL_SET "set" |
#define | QSF_CONDITIONAL_ELSE "else" |
#define | QSF_OPTION "option" |
#define | QSF_FORMATTING_OPTION "format" |
Typedefs | |
typedef qsf_object_set | qsf_objects |
Holds a description of the QofObject. | |
typedef qsf_metadata | qsf_param |
QSF Parameters. | |
typedef qsf_validates | qsf_validator |
Validation metadata. | |
Enumerations | |
enum | qsf_type { QSF_UNDEF = 0, IS_QSF_MAP, IS_QSF_OBJ, HAVE_QSF_MAP, OUR_QSF_OBJ } |
enum | QsfStatus { QSF_NO_OBJECT = 0, QSF_DEFINED_OBJECT, QSF_REGISTERED_OBJECT, QSF_CALCULATED_OBJECT, QSF_INVALID_OBJECT } |
Status of various object during mapping. More... | |
Functions | |
gint | qsf_compare_tag_strings (const xmlChar *node_name, gchar *tag_name) |
shorthand function | |
gint | qsf_strings_equal (const xmlChar *node_name, gchar *tag_name) |
shorthand function | |
gint | qsf_is_element (xmlNodePtr a, xmlNsPtr ns, gchar *c) |
shorthand function | |
gint | qsf_check_tag (qsf_param *params, gchar *qof_type) |
shorthand function | |
void | qsf_object_validation_handler (xmlNodePtr child, xmlNsPtr ns, qsf_validator *valid) |
Checks all incoming objects for QOF registration. | |
gboolean | qsf_is_valid (const gchar *schema_dir, const gchar *schema_filename, xmlDocPtr doc) |
Compares an xmlDoc in memory against the schema file. | |
GList ** | qsf_map_prepare_list (GList **maps) |
Prepare the default list of maps. | |
void | qsf_book_node_handler (xmlNodePtr child, xmlNsPtr qsf_ns, qsf_param *params) |
Book and book-guid node handler. | |
KvpValue * | string_to_kvp_value (const gchar *content, KvpValueType type) |
Convert a string value into KvpValue. | |
void | qsf_valid_foreach (xmlNodePtr parent, qsf_validCB cb, struct qsf_node_iterate *iter, qsf_validator *valid) |
void | qsf_node_foreach (xmlNodePtr parent, qsf_nodeCB cb, struct qsf_node_iterate *iter, qsf_param *params) |
xmlDocPtr | qsf_object_convert (xmlDocPtr mapDoc, xmlNodePtr qsf_root, qsf_param *params) |
Convert between QSF objects. | |
void | qsf_object_node_handler (xmlNodePtr child, xmlNsPtr qsf_ns, qsf_param *params) |
#define MAP_CALCULATE_TAG "calculate" |
One calculation for every parameter that needs to be set.
QSF follows the same rule as qof_book_merge. Only if a getter and a setter function are defined for a parameter is it available to QSF. If a QofAccessFunc and QofSetterFunc are both defined for any QofObject parameter, that parameter MUST be calculated in any map that defines that object.
#define MAP_DEFAULT_TAG "default" |
User editable defaults for data not available within the available QSF objects.
Some defaults will relate to how to format descriptive dates, whether discount should be considered, which account to use for certain QSF data from applications that do not use accounts.
Some defaults are pre-defined and cannot be over-written:
Attributes (All are mandatory):
name The text name for this default. Certain pre-defined defaults exist but user- or map-defined defaults can have any unique text name. Spaces are NOT allowed, use undersccores instead. The value of name must not duplicate any existing default, define, object or parameter unless the special type, enum, is used.
type QOF_TYPE - must be one of the recognised QOF data types for the qof_version in use or the special type, enum.
value Text representation of the required value. For numeric, use the format [0-9]?/[0-9]?
QSF deals with partial QofBooks - each object is fully described but the book does not have to contain any specific object types or have any particular structure. To merge partial books into usual QofBook data sources, the map must deal with entities that need to be referenced in the target QofBook but which simply do not exist in the QofBook used to generate the QSF. e.g. pilot-link knows nothing of Accounts yet when QSF creates a gncInvoice from qof-datebook, gncInvoice needs to know the GUID of certain accounts in the target QofBook. This is handled in the map by specifying the name of the account as a default for that map. When imported, the QSF QofBackend looks up the object required using the name of the parameter to obtain the parameter type. This is the only situation where QSF converts between QOF data types. A string description of the required object is converted to the GUID for that specific entity. The map cannot contain the GUID as it is generic and used by multiple users.
#define MAP_DEFINE_TAG "define" |
#define MAP_DEFINITION_TAG "definition" |
Second level container for defined objects
Attributes: qof_version - Taken from the QOF_OBJECT_VERSION macro in QOF, At the time of QSF development, QOF_OBJECT_VERSION is defined as 3. All QSF maps and QSF objects must use the same qof_version which in turn must match the QOF_OBJECT_VERSION for the QOF library in use by the calling process.
No text content allowed.
#define MAP_E_TYPE "e_type" |
Validates the objects defined in the map
The e_type will be used to match incoming QSF objects with the relevant QSF map. The value of the e_type must be the value of the e_type for that object in the originating QOF application. The define tag must contain the value of the description of the same object in the same originating QOF application.
#define MAP_ENUM_TYPE "enum" |
#define MAP_ITERATE_ATTR "foreach" |
#define MAP_NAME_ATTR "name" |
#define MAP_OBJECT_ATTR "object" |
#define MAP_OBJECT_TAG "object" |
Contains all the calculations to make one object from others.
Note that creating an object for the import application can involve using data from more than one QSF object, as well as defaults and lookups in the import application itself. Conditionals, simple arithmetic and date/time formatting options are also available.
#define MAP_QOF_VERSION "qof_version" |
#define MAP_ROOT_TAG "qsf-map" |
#define MAP_TYPE_ATTR "type" |
#define MAP_VALUE_ATTR "value" |
The value of the tag, used in defaults and calculations.
The value of a default is a string representation of the value to be inserted into the calculation where the default is used.
The value of a calculation is the name of the parameter that will be set by that calculation.
#define QSF_BOOK_COUNT "count" |
#define QSF_BOOK_GUID "book-guid" |
#define QSF_BOOK_TAG "book" |
#define QSF_CONDITIONAL "if" |
child of calculate.
Conditionals can reference objects as if within the original application. In operation, the map is overlaid across both sets of defined objects, an import object in the source application and an output object for the destination object. The current import and output QSF objects are therefore always available to the map. Conditionals can reference parameter as well as object values.
#define QSF_CONDITIONAL_ELSE "else" |
Alternative
if(){} else{} is also supported. Nesting of conditionals causes problems for validating the final map against any sensible XML Schema and a map that does not validate will be rejected. When editing conditionals in a QSF map, ALWAYS validate the map using xmllint. If necessary, define a variable at the foot of the definitions block, using a similar syntax to a default, then use that variable in another conditional
variable name="my_rate" type="numeric" value="0/1"
The syntax for xmllint is:
xmllint --schema <schema file> <qsf-file>
Use the qsf-object.xsd.xml schema for objects and qsf-map.xsd.xml for map files.
e.g. xmllint --schema qsf-object.xsd.xml --noout qof-qsf.xml
#define QSF_CONDITIONAL_SET "set" |
Assignment statement
Map assignments can use the native values within the output object. The output object must support setting the relevant parameter using the value exactly as given in the map because the relevant set() function will be called using this value. This may reduce the readability of the map but the relevant application could also be modified to support a more readable set function.
#define QSF_DATE_LENGTH MAX_DATE_LENGTH |
#define QSF_DEFAULT_NS "http://qof.sourceforge.net/" |
#define QSF_FORMATTING_OPTION "format" |
How to format dates/times
When the QSF map uses a date/time value as a string, the formatting can be adjusted to personal preference. format will only be evaluated if the calculated parameter is a QOF_TYPE_STRING - any format attributes on other data types will be ignored.
#define QSF_MAP_SCHEMA "qsf-map.xsd.xml" |
#define QSF_OBJECT_COUNT "count" |
#define QSF_OBJECT_KVP "path" |
#define QSF_OBJECT_SCHEMA "qsf-object.xsd.xml" |
#define QSF_OBJECT_TAG "object" |
#define QSF_OBJECT_TYPE "type" |
#define QSF_OPTION "option" |
#define QSF_QOF_VERSION QOF_OBJECT_VERSION |
#define QSF_XML_BOOLEAN_TEST "true" |
#define QSF_XSD_TIME QOF_UTC_DATE_FORMAT |
xsd:dateTime format in coordinated universal time, UTC.
You can reproduce the string from the GNU/Linux command line using the date utility:
date -u +Y-m-dTH:M:SZ
2004-12-12T23:39:11Z
The datestring must be timezone independent and include all specified fields.
Remember to use gmtime() NOT localtime()!. From the command line, use the -u switch with the date command: date -u
To generate a timestamp based on a real time, use the qsf_time_now and qsf_time_string defaults.
qsf_time_now : Format: QOF_TYPE_DATE. The current time taken from the moment the default is read into a QSF object at runtime.
qsf_time_string : Format: QOF_TYPE_STRING. The current timestamp taken from the moment the default is read into a QSF object at runtime. This form is used when the output parameter needs a formatted date string, not an actual date object. The format is determined by the optional format attribute of the set tag which takes the same operators as the GNU C Library for strftime() and output may therefore be dependent on the locale of the calling process - take care. Default value is F, used when qsf_time_string is set without the format attribute.
Both defaults use UTC.
typedef void(*) qsf_nodeCB(xmlNodePtr, xmlNsPtr, qsf_param *) |
map and qsf object callback
This callback cannot do both the map and the validation tasks because validation sometimes needs to be done without qsf_params.
e.g. when selecting which backend should be used for a particular data source where two or more backends share the same access_method.
typedef struct qsf_object_set qsf_objects |
Holds a description of the QofObject.
Used when converting QOF objects from another application. The incoming, unknown, objects need to be stored prior to conversion. This allows many-to-many conversions where an invoice can receive data from an incoming expense AND datebook and use data from an incoming contacts object to lookup the customer for the invoice.
typedef struct qsf_metadata qsf_param |
QSF Parameters.
This struct is a catch-all for all parameters required for various stages of the process. There are lots of elements here that will finally be removed.
typedef struct qsf_validates qsf_validator |
Validation metadata.
The validation is a separate parse with separate data. This is used to determine which backend should load the data.
typedef void(*) qsf_validCB(xmlNodePtr, xmlNsPtr, qsf_validator *) |
enum qsf_type |
Definition at line 41 of file qsf-xml.h.
00042 { 00043 QSF_UNDEF = 0, 00044 IS_QSF_MAP, 00045 IS_QSF_OBJ, 00046 HAVE_QSF_MAP, 00047 OUR_QSF_OBJ, 00048 } qsf_type;
enum QsfStatus |
Status of various object during mapping.
When handling a map, the incoming QSF objects are not registered with this instance of QOF - they originate from another QOF user. Each object in a map needs to be defined. If the object is registered, the map is checked to locate a calculation that can be used to generate this object. If the object is not registered, the incoming QSF is checked to ensure it provides the object data for the calculation. If anything goes wrong, QSF_INVALID_OBJECT is used.
Maps can be unidirectional or bidirectional so QOF registration is used to determine which calculations should be used and which should be ignored.
All QSF_REGISTERED_OBJECT types need a calculation - if any types remain tagged as QSF_REGISTERED_OBJECT when the map validation is complete, the validation must fail. The only acceptable end values for QsfStatus are QSF_DEFINED_OBJECT, QSF_CALCULATED_OBJECT or QSF_INVALID_OBJECT.
Definition at line 353 of file qsf-xml.h.
00354 { 00355 QSF_NO_OBJECT = 0, 00356 QSF_DEFINED_OBJECT, 00359 QSF_REGISTERED_OBJECT, 00361 QSF_CALCULATED_OBJECT, 00362 QSF_INVALID_OBJECT 00363 } QsfStatus;
gboolean is_our_qsf_object | ( | const gchar * | path | ) |
Validate a QSF file.
path | Absolute or relative path to the file to be validated |
Files that pass the test can be imported into the QOF appliction without the need for a QSF map.
< Name of the QSF Object Schema.
< Name of the QSF Object Schema.
Definition at line 177 of file qsf-xml.c.
00178 { 00179 xmlDocPtr doc; 00180 struct qsf_node_iterate iter; 00181 xmlNodePtr object_root; 00182 qsf_validator valid; 00183 gint table_count; 00184 00185 g_return_val_if_fail ((path != NULL), FALSE); 00186 doc = xmlParseFile (path); 00187 if (doc == NULL) 00188 { 00189 return FALSE; 00190 } 00191 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) 00192 { 00193 PINFO (" validation failed %s %s %s", QSF_SCHEMA_DIR, 00194 QSF_OBJECT_SCHEMA, path); 00195 return FALSE; 00196 } 00197 object_root = xmlDocGetRootElement (doc); 00198 /* check that all objects in the file are already registered in QOF */ 00199 valid.object_table = g_hash_table_new (g_str_hash, g_str_equal); 00200 valid.qof_registered_count = 0; 00201 valid.valid_object_count = 0; 00202 iter.ns = object_root->ns; 00203 qsf_valid_foreach (object_root, qsf_object_validation_handler, &iter, 00204 &valid); 00205 table_count = g_hash_table_size (valid.object_table); 00206 g_hash_table_destroy (valid.object_table); 00207 xmlFreeDoc (doc); 00208 if (table_count == valid.qof_registered_count) 00209 { 00210 return TRUE; 00211 } 00212 return FALSE; 00213 }
gboolean is_our_qsf_object_be | ( | qsf_param * | params | ) |
Validate a QSF file and determine type.
params | Pointer to qsf_param context |
Files that pass the test can be imported into the QOF appliction without the need for a QSF map.
< Name of the QSF Object Schema.
Definition at line 240 of file qsf-xml.c.
00241 { 00242 xmlDocPtr doc; 00243 struct qsf_node_iterate iter; 00244 xmlNodePtr object_root; 00245 qsf_validator valid; 00246 gint table_count; 00247 00248 g_return_val_if_fail ((params != NULL), FALSE); 00249 if (params->filepath == NULL) 00250 { 00251 qof_backend_set_error (params->be, ERR_FILEIO_FILE_NOT_FOUND); 00252 return FALSE; 00253 } 00254 if (params->file_type != QSF_UNDEF) 00255 { 00256 return FALSE; 00257 } 00258 doc = xmlParseFile (params->filepath); 00259 if (doc == NULL) 00260 { 00261 qof_backend_set_error (params->be, ERR_FILEIO_PARSE_ERROR); 00262 return FALSE; 00263 } 00264 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) 00265 { 00266 qof_backend_set_error (params->be, ERR_QSF_INVALID_OBJ); 00267 xmlFreeDoc (doc); 00268 return FALSE; 00269 } 00270 params->file_type = IS_QSF_OBJ; 00271 object_root = xmlDocGetRootElement (doc); 00272 xmlFreeDoc (doc); 00273 valid.object_table = g_hash_table_new (g_str_hash, g_str_equal); 00274 valid.qof_registered_count = 0; 00275 iter.ns = object_root->ns; 00276 qsf_valid_foreach (object_root, qsf_object_validation_handler, &iter, 00277 &valid); 00278 table_count = g_hash_table_size (valid.object_table); 00279 if (table_count == valid.qof_registered_count) 00280 { 00281 g_hash_table_destroy (valid.object_table); 00282 qof_backend_set_error (params->be, ERR_BACKEND_NO_ERR); 00283 return TRUE; 00284 } 00285 g_hash_table_destroy (valid.object_table); 00286 qof_backend_set_error (params->be, ERR_QSF_NO_MAP); 00287 return FALSE; 00288 }
gboolean is_qsf_map | ( | const gchar * | path | ) |
Validate a QSF map file.
path | Absolute or relative path to the file to be validated |
The file is validated aginst the QSF map schema, qsf-map.xsd.xsml. This function is called by is_qsf_object. If called directly, the map file is validated and closed, no data is retrieved. QSF maps do not contain user data but are used to import QSF object files from other applications.
< Name of the QSF Map Schema.
Definition at line 453 of file qsf-xml-map.c.
00453 { 00454 qof_backend_set_error (params->be, ERR_QSF_BAD_MAP); 00455 PERR (" ERR_QSF_BAD_MAP set"); 00456 return; 00457 } 00458 } 00460 else 00461 { 00462 if (NULL == g_hash_table_lookup (params->qsf_default_hash, 00463 xmlGetProp (child, BAD_CAST MAP_NAME_ATTR))) 00464 { 00465 g_hash_table_insert (params->qsf_default_hash, 00466 xmlGetProp (child, BAD_CAST MAP_NAME_ATTR), child); 00467 } 00468 else 00469 /* if(0 != xmlHashAddEntry(params->default_map, 00470 xmlGetProp(child_node, MAP_NAME_ATTR), child_node))*/ 00471 { 00472 qof_backend_set_error (params->be, ERR_QSF_BAD_MAP); 00473 PERR (" ERR_QSF_BAD_MAP set"); 00474 return; 00475 } 00476 } 00477 } 00478 } 00479 00480 static void 00481 qsf_map_top_node_handler (xmlNodePtr child, xmlNsPtr ns, 00482 qsf_param * params) 00483 { 00484 xmlChar *qof_version; 00485 gchar *buff; 00486 struct qsf_node_iterate iter; 00487 00488 if (!params->qsf_define_hash) 00489 return;
gboolean is_qsf_map_be | ( | qsf_param * | params | ) |
Validate a QSF map file.
params | Pointer to qsf_param context |
< Name of the QSF Map Schema.
Definition at line 405 of file qsf-xml-map.c.
00405 { 00406 xmlChar *qsf_enum; 00407 gchar *iterate; 00408 00409 g_return_if_fail (params->qsf_define_hash != NULL); 00410 iterate = NULL; 00411 if (qsf_is_element (child, ns, MAP_DEFINE_TAG)) 00412 { 00413 iterate = xmlGetProp (child, MAP_ITERATE_ATTR); 00414 if ((qof_util_bool_to_int (iterate) == 1) && 00415 (qof_class_is_registered 00416 (xmlGetProp (child, BAD_CAST MAP_E_TYPE)))) 00417 { 00418 params->qof_foreach = xmlGetProp (child, BAD_CAST MAP_E_TYPE); 00419 PINFO (" iterating over '%s' objects", params->qof_foreach); 00420 } 00421 if (NULL == g_hash_table_lookup (params->qsf_define_hash, 00422 xmlGetProp (child, BAD_CAST MAP_E_TYPE))) 00423 { 00424 g_hash_table_insert (params->qsf_define_hash, 00425 xmlGetProp (child, BAD_CAST MAP_E_TYPE), 00426 params->child_node); 00427 } 00428 else 00429 { 00430 qof_backend_set_error (params->be, ERR_QSF_BAD_MAP); 00431 PERR (" ERR_QSF_BAD_MAP set"); 00432 return; 00433 } 00434 } 00435 if (qsf_is_element (child, ns, MAP_DEFAULT_TAG)) 00436 { 00437 if (qsf_strings_equal 00438 (xmlGetProp (child, BAD_CAST MAP_TYPE_ATTR), MAP_ENUM_TYPE)) 00439 { 00440 qsf_enum = xmlNodeGetContent (child); 00442 PERR (" enum todo incomplete"); 00446 if (NULL == g_hash_table_lookup (params->qsf_default_hash, 00447 xmlNodeGetContent (child))) 00448 { 00449 g_hash_table_insert (params->qsf_default_hash, 00450 xmlNodeGetContent (child), child);
gboolean is_qsf_object | ( | const gchar * | path | ) |
Validate a QSF file and identify a suitable QSF map.
path | Absolute or relative path to the file to be validated. |
The file is validated against the QSF object schema, qsf-object.xsd.xml and each object described in the file is checked to find out if a suitable QSF map exists. Map files are accepted if all objects described in the QSF object file are defined in the QSF map.
< Name of the QSF Object Schema.
Definition at line 216 of file qsf-xml.c.
00217 { 00218 xmlDocPtr doc; 00219 00220 g_return_val_if_fail ((path != NULL), FALSE); 00221 if (path == NULL) 00222 { 00223 return FALSE; 00224 } 00225 doc = xmlParseFile (path); 00226 if (doc == NULL) 00227 { 00228 return FALSE; 00229 } 00230 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) 00231 { 00232 return FALSE; 00233 } 00234 /* Note cannot test against a map here, so if the file is valid QSF, 00235 accept it and work out the details later. */ 00236 return TRUE; 00237 }
gboolean is_qsf_object_be | ( | qsf_param * | params | ) |
Validate a QSF file and identify a suitable QSF map.
params | Pointer to qsf_param context |
The file is validated against the QSF object schema, qsf-object.xsd.xml and each object described in the file is checked to find out if a suitable QSF map exists. Map files are accepted if all objects described in the QSF object file are defined in the QSF map.
< Name of the QSF Object Schema.
Definition at line 291 of file qsf-xml.c.
00292 { 00293 gboolean result; 00294 xmlDocPtr doc; 00295 GList *maps; 00296 gchar *path; 00297 00298 g_return_val_if_fail ((params != NULL), FALSE); 00299 path = g_strdup (params->filepath); 00300 if (path == NULL) 00301 { 00302 qof_backend_set_error (params->be, ERR_FILEIO_FILE_NOT_FOUND); 00303 return FALSE; 00304 } 00305 /* skip validation if is_our_qsf_object has already been called. */ 00306 if (ERR_QSF_INVALID_OBJ == qof_backend_get_error (params->be)) 00307 { 00308 return FALSE; 00309 } 00310 if (params->file_type == QSF_UNDEF) 00311 { 00312 doc = xmlParseFile (path); 00313 if (doc == NULL) 00314 { 00315 qof_backend_set_error (params->be, ERR_FILEIO_PARSE_ERROR); 00316 return FALSE; 00317 } 00318 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) 00319 { 00320 qof_backend_set_error (params->be, ERR_QSF_INVALID_OBJ); 00321 return FALSE; 00322 } 00323 } 00324 result = FALSE; 00325 /* retrieve list of maps from config frame. */ 00326 for (maps = params->map_files; maps; maps = maps->next) 00327 { 00328 QofBackendError err; 00329 result = is_qsf_object_with_map_be (maps->data, params); 00330 err = qof_backend_get_error (params->be); 00331 if ((err == ERR_BACKEND_NO_ERR) && result) 00332 { 00333 params->map_path = maps->data; 00334 PINFO ("map chosen = %s", params->map_path); 00335 break; 00336 } 00337 /* pop the error back on the stack. */ 00338 else 00339 { 00340 qof_backend_set_error (params->be, err); 00341 } 00342 } 00343 return result; 00344 }
gboolean is_qsf_object_with_map | ( | const gchar * | path, | |
gchar * | map_file | |||
) |
Validate a QSF file and a selected QSF map.
path | Absolute or relative path to the selected QSF object file | |
map_file | Name of the QSF map file, located in QSF_SCHEMA_DIR. |
< Name of the QSF Object Schema.
Definition at line 375 of file qsf-xml-map.c.
00375 { 00376 return FALSE; 00377 } 00378 doc = xmlParseFile (path); 00379 if (doc == NULL) 00380 { 00381 return FALSE; 00382 } 00383 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_MAP_SCHEMA, doc)) 00384 { 00385 return FALSE; 00386 } 00387 map_root = xmlDocGetRootElement (doc); 00388 map_ns = map_root->ns; 00389 iter.ns = map_ns; 00390 valid.error_state = ERR_BACKEND_NO_ERR; 00391 valid.map_table = g_hash_table_new (g_str_hash, g_str_equal); 00392 qsf_valid_foreach (map_root, qsf_map_validation_handler, &iter, 00393 &valid); 00394 if (valid.error_state != ERR_BACKEND_NO_ERR) 00395 { 00396 g_hash_table_destroy (valid.map_table); 00397 return FALSE; 00398 } 00399 g_hash_table_destroy (valid.map_table); 00400 return TRUE; 00401 } 00402
gboolean is_qsf_object_with_map_be | ( | gchar * | map_path, | |
qsf_param * | params | |||
) |
Validate a QSF file and a selected QSF map.
map_path | Absolute or relative path to the selected QSF map file | |
params | Pointer to qsf_param context |
This backend twin also sets QofBackendError codes.
< Name of the QSF Object Schema.
Definition at line 332 of file qsf-xml-map.c.
00336 { 00337 qof_backend_set_error (params->be, ERR_FILEIO_PARSE_ERROR); 00338 return FALSE; 00339 } 00340 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_MAP_SCHEMA, doc)) 00341 { 00342 qof_backend_set_error (params->be, ERR_QSF_INVALID_MAP); 00343 return FALSE; 00344 } 00345 map_root = xmlDocGetRootElement (doc); 00346 map_ns = map_root->ns; 00347 iter.ns = map_ns; 00348 valid.object_table = g_hash_table_new (g_str_hash, g_str_equal); 00349 valid.map_table = g_hash_table_new (g_str_hash, g_str_equal); 00350 valid.error_state = ERR_BACKEND_NO_ERR; 00351 qsf_valid_foreach (map_root, qsf_map_validation_handler, &iter, 00352 &valid); 00353 if (valid.error_state != ERR_BACKEND_NO_ERR) 00354 { 00355 qof_backend_set_error (params->be, valid.error_state); 00356 g_hash_table_destroy (valid.object_table); 00357 return FALSE; 00358 } 00359 qof_backend_get_error (params->be); 00360 g_hash_table_destroy (valid.object_table); 00361 return TRUE; 00362 } 00363 00364 gboolean 00365 is_qsf_map (const gchar * path) 00366 { 00367 xmlDocPtr doc; 00368 struct qsf_node_iterate iter; 00369 qsf_validator valid; 00370 xmlNodePtr map_root; 00371 xmlNsPtr map_ns; 00372
void qsf_book_node_handler | ( | xmlNodePtr | child, | |
xmlNsPtr | qsf_ns, | |||
qsf_param * | params | |||
) |
Book and book-guid node handler.
Reads the book count="" attribute (currently only 1 QofBook is supported per QSF object file) Sets the book-guid as the GUID of the current QofBackend QofBook in qsf_param. Calls the next handler, qsf_object_node_handler, with the child of the book tag.
< First level child: book tag - the QofBook.
< Sequential counter of each book in this file
< QOF GUID tag for the QofBook described by this QSF object file
< QOF GUID tag for the QofBook described by this QSF object file
Definition at line 413 of file qsf-xml.c.
00413 { 00414 gchar *book_count_s, *tail; 00415 gint book_count; 00416 xmlNodePtr child_node; 00417 struct qsf_node_iterate iter; 00418 gchar *buffer; 00419 GUID book_guid; 00420 00421 g_return_if_fail (child); 00422 g_return_if_fail (params); 00423 ENTER (" child=%s", child->name); 00424 if (qsf_is_element (child, ns, QSF_BOOK_TAG)) 00425 { 00426 book_count_s = 00427 (gchar *) xmlGetProp (child, BAD_CAST QSF_BOOK_COUNT); 00428 if (book_count_s) 00429 { 00430 book_count = (gint) strtol (book_count_s, &tail, 0); 00431 /* More than one book not currently supported. */ 00432 g_free (book_count_s); 00433 g_return_if_fail (book_count == 1); 00434 } 00435 iter.ns = ns; 00436 child_node = child->children->next; 00437 if (qsf_is_element (child_node, ns, QSF_BOOK_GUID)) 00438 { 00439 DEBUG (" trying to set book GUID"); 00440 buffer = BAD_CAST xmlNodeGetContent (child_node); 00441 g_return_if_fail (TRUE == string_to_guid (buffer, &book_guid)); 00442 qof_entity_set_guid ((QofEntity *) params->book, &book_guid); 00443 xmlNewChild (params->output_node, params->qsf_ns, 00444 BAD_CAST QSF_BOOK_GUID, BAD_CAST buffer); 00445 xmlFree (buffer); 00446 } 00447 qsf_node_foreach (child, qsf_object_node_handler, &iter, params); 00448 } 00449 LEAVE (" "); 00450 } 00451 }
gint qsf_check_tag | ( | qsf_param * | params, | |
gchar * | qof_type | |||
) |
shorthand function
This may look repetitive but each one is used separately as well as in a block.
Definition at line 69 of file qsf-xml.c.
00070 { 00071 return qsf_is_element (params->child_node, params->qsf_ns, qof_type); 00072 }
gint qsf_compare_tag_strings | ( | const xmlChar * | node_name, | |
gchar * | tag_name | |||
) |
gint qsf_is_element | ( | xmlNodePtr | a, | |
xmlNsPtr | ns, | |||
gchar * | c | |||
) |
shorthand function
This may look repetitive but each one is used separately as well as in a block.
Definition at line 55 of file qsf-xml.c.
00056 { 00057 g_return_val_if_fail (a != NULL, 0); 00058 g_return_val_if_fail (ns != NULL, 0); 00059 g_return_val_if_fail (c != NULL, 0); 00060 if ((a->ns == ns) && (a->type == XML_ELEMENT_NODE) && 00061 qsf_strings_equal (a->name, c)) 00062 { 00063 return 1; 00064 } 00065 return 0; 00066 }
gboolean qsf_is_valid | ( | const gchar * | schema_dir, | |
const gchar * | schema_filename, | |||
xmlDocPtr | doc | |||
) |
Compares an xmlDoc in memory against the schema file.
schema_dir | set at compile time to $prefix/share/qsf/ | |
schema_filename | Either the QSF Object Schema or the QSF Map Schema. | |
doc | The xmlDoc read from the file using libxml2. |
Incorrect validation will result in output to the terminal window.
Definition at line 75 of file qsf-xml.c.
00077 { 00078 xmlSchemaParserCtxtPtr qsf_schema_file; 00079 xmlSchemaPtr qsf_schema; 00080 xmlSchemaValidCtxtPtr qsf_context; 00081 gchar *schema_path; 00082 gint result; 00083 00084 g_return_val_if_fail (doc || schema_filename, FALSE); 00085 schema_path = g_strdup_printf ("%s/%s", schema_dir, schema_filename); 00086 qsf_schema_file = xmlSchemaNewParserCtxt (schema_path); 00087 qsf_schema = xmlSchemaParse (qsf_schema_file); 00088 qsf_context = xmlSchemaNewValidCtxt (qsf_schema); 00089 result = xmlSchemaValidateDoc (qsf_context, doc); 00090 xmlSchemaFreeParserCtxt (qsf_schema_file); 00091 xmlSchemaFreeValidCtxt (qsf_context); 00092 xmlSchemaFree (qsf_schema); 00093 g_free (schema_path); 00094 if (result == 0) 00095 { 00096 return TRUE; 00097 } 00098 return FALSE; 00099 }
GList** qsf_map_prepare_list | ( | GList ** | maps | ) |
Prepare the default list of maps.
Prepend the default maps to the supplied GList.
The GList remains the property of the caller.
Definition at line 167 of file qsf-backend.c.
00168 { 00169 /* Add new map filenames here. */ 00171 *maps = g_list_prepend (*maps, "pilot-qsf-GnuCashInvoice.xml"); 00172 *maps = g_list_prepend (*maps, "pilot-qsf-gncCustomer.xml"); 00173 return maps; 00174 }
void qsf_node_foreach | ( | xmlNodePtr | parent, | |
qsf_nodeCB | cb, | |||
struct qsf_node_iterate * | iter, | |||
qsf_param * | params | |||
) |
Iterate over the children of the parent node.
Only iterates over the immediate children of the parent - this function is not recursive.
Definition at line 116 of file qsf-xml.c.
00118 { 00119 xmlNodePtr cur_node; 00120 00121 g_return_if_fail (iter->ns); 00122 iter->fcn = &cb; 00123 for (cur_node = parent->children; cur_node != NULL; 00124 cur_node = cur_node->next) 00125 { 00126 cb (cur_node, iter->ns, params); 00127 } 00128 }
xmlDocPtr qsf_object_convert | ( | xmlDocPtr | mapDoc, | |
xmlNodePtr | qsf_root, | |||
qsf_param * | params | |||
) |
Convert between QSF objects.
This is the main workhorse of the conversion between QSF objects using maps.
mapDoc | The map document, parsed by libxml2. | |
qsf_root | The top node of the QSF object to be converted using the map. | |
params | The QSF backend parameters. |
< The current XML version.
< The top level root tag
< First level child: book tag - the QofBook.
< Sequential counter of each book in this file
< Contains all the calculations to make one object from others.
Note that creating an object for the import application can involve using data from more than one QSF object, as well as defaults and lookups in the import application itself. Conditionals, simple arithmetic and date/time formatting options are also available.
< QSF will NOT convert between QOF types.
QSF will allow a conditional to use a parameter of one type to determine the value from a parameter of another type, but the final value assigned MUST be of the same type as the parent calculation.
Definition at line 1325 of file qsf-xml-map.c.
void qsf_object_node_handler | ( | xmlNodePtr | child, | |
xmlNsPtr | qsf_ns, | |||
qsf_param * | params | |||
) |
Despite the name, this function handles the QSF object book tag AND the object tags.
Used to parse object and map files.
< Second level child: object tag
< QSF parameter name for object type specifiers
< Sequential counter for each QSF object in this file
Definition at line 376 of file qsf-xml.c.
00378 { 00379 struct qsf_node_iterate iter; 00380 qsf_objects *object_set; 00381 gchar *tail, *object_count_s; 00382 gint64 c; 00383 00384 g_return_if_fail (child != NULL); 00385 g_return_if_fail (qsf_ns != NULL); 00386 params->qsf_ns = qsf_ns; 00387 if (qsf_is_element (child, qsf_ns, QSF_OBJECT_TAG)) 00388 { 00389 params->qsf_parameter_hash = NULL; 00390 c = 0; 00391 object_set = g_new (qsf_objects, 1); 00392 params->object_set = object_set; 00393 object_set->object_count = 0; 00394 object_set->parameters = 00395 g_hash_table_new (g_str_hash, g_str_equal); 00396 object_set->object_type = ((gchar *) xmlGetProp (child, 00397 BAD_CAST QSF_OBJECT_TYPE)); 00398 object_count_s = ((gchar *) xmlGetProp (child, 00399 BAD_CAST QSF_OBJECT_COUNT)); 00400 c = (gint64) strtol (object_count_s, &tail, 0); 00401 object_set->object_count = (gint) c; 00402 g_free (object_count_s); 00403 params->qsf_object_list = 00404 g_list_prepend (params->qsf_object_list, object_set); 00405 iter.ns = qsf_ns; 00406 params->qsf_parameter_hash = object_set->parameters; 00407 qsf_node_foreach (child, qsf_parameter_handler, &iter, params); 00408 } 00409 } 00410
void qsf_object_validation_handler | ( | xmlNodePtr | child, | |
xmlNsPtr | ns, | |||
qsf_validator * | valid | |||
) |
Checks all incoming objects for QOF registration.
Sums all existing objects in the QSF and counts the number of those objects that are also registered with QOF in the host application.
< Second level child: object tag
< QSF parameter name for object type specifiers
Definition at line 131 of file qsf-xml.c.
00133 { 00134 xmlNodePtr cur_node; 00135 xmlChar *object_declaration; 00136 guint count; 00137 QsfStatus type; 00138 gboolean is_registered; 00139 00140 count = 0; 00141 type = QSF_NO_OBJECT; 00142 is_registered = FALSE; 00143 for (cur_node = child->children; cur_node != NULL; 00144 cur_node = cur_node->next) 00145 { 00146 if (qsf_is_element (cur_node, ns, QSF_OBJECT_TAG)) 00147 { 00148 object_declaration = 00149 xmlGetProp (cur_node, BAD_CAST QSF_OBJECT_TYPE); 00150 is_registered = qof_class_is_registered (object_declaration); 00151 if (is_registered) 00152 { 00153 type = QSF_REGISTERED_OBJECT; 00154 } 00155 else 00156 { 00157 type = QSF_DEFINED_OBJECT; 00158 } 00159 xmlFree (object_declaration); 00160 count = g_hash_table_size (valid->object_table); 00161 g_hash_table_insert (valid->object_table, object_declaration, 00162 GINT_TO_POINTER (type)); 00163 /* if insert was successful - i.e. object is unique so far */ 00164 if (g_hash_table_size (valid->object_table) > count) 00165 { 00166 valid->valid_object_count++; 00167 if (is_registered) 00168 { 00169 valid->qof_registered_count++; 00170 } 00171 } 00172 } 00173 } 00174 }
gint qsf_strings_equal | ( | const xmlChar * | node_name, | |
gchar * | tag_name | |||
) |
void qsf_valid_foreach | ( | xmlNodePtr | parent, | |
qsf_validCB | cb, | |||
struct qsf_node_iterate * | iter, | |||
qsf_validator * | valid | |||
) |
Validate the children of the parent node.
Definition at line 102 of file qsf-xml.c.
00104 { 00105 xmlNodePtr cur_node; 00106 00107 iter->v_fcn = &cb; 00108 for (cur_node = parent->children; cur_node != NULL; 00109 cur_node = cur_node->next) 00110 { 00111 cb (cur_node, iter->ns, valid); 00112 } 00113 }
KvpValue* string_to_kvp_value | ( | const gchar * | content, | |
KvpValueType | type | |||
) |
Convert a string value into KvpValue.
Partner to kvp_value_to_string. Given the type of KvpValue required, attempts to convert the string into that type of value.
content | A string representation of the value, ideally as output by kvp_value_to_string. | |
type | KvpValueType of the intended KvpValue |
< xsd:dateTime format in coordinated universal time, UTC.
You can reproduce the string from the GNU/Linux command line using the date utility:
date -u +Y-m-dTH:M:SZ
2004-12-12T23:39:11Z
The datestring must be timezone independent and include all specified fields.
Remember to use gmtime() NOT localtime()!. From the command line, use the -u switch with the date command: date -u
To generate a timestamp based on a real time, use the qsf_time_now and qsf_time_string defaults.
qsf_time_now : Format: QOF_TYPE_DATE. The current time taken from the moment the default is read into a QSF object at runtime.
qsf_time_string : Format: QOF_TYPE_STRING. The current timestamp taken from the moment the default is read into a QSF object at runtime. This form is used when the output parameter needs a formatted date string, not an actual date object. The format is determined by the optional format attribute of the set tag which takes the same operators as the GNU C Library for strftime() and output may therefore be dependent on the locale of the calling process - take care. Default value is F, used when qsf_time_string is set without the format attribute.
Both defaults use UTC.
Definition at line 1198 of file qsf-backend.c.
01207 { 01208 case KVP_TYPE_GINT64: 01209 { 01210 errno = 0; 01211 cm_i64 = strtoll (content, &tail, 0); 01212 if (errno == 0) 01213 { 01214 return kvp_value_new_gint64 (cm_i64); 01215 } 01216 break; 01217 } 01218 case KVP_TYPE_DOUBLE: 01219 { 01220 errno = 0; 01221 cm_double = strtod (content, &tail); 01222 if (errno == 0) 01223 { 01224 return kvp_value_new_double (cm_double); 01225 } 01226 break; 01227 } 01228 case KVP_TYPE_NUMERIC: 01229 { 01230 qof_numeric_from_string (content, &cm_numeric); 01231 return kvp_value_new_gnc_numeric (cm_numeric); 01232 break; 01233 } 01234 case KVP_TYPE_STRING: 01235 { 01236 return kvp_value_new_string (content); 01237 break; 01238 } 01239 case KVP_TYPE_GUID: 01240 { 01241 cm_guid = g_new (GUID, 1); 01242 if (TRUE == string_to_guid (content, cm_guid)) 01243 { 01244 return kvp_value_new_guid (cm_guid); 01245 } 01246 break; 01247 } 01248 case KVP_TYPE_TIME : 01249 { 01250 QofDate *qd; 01251 QofTime *qt; 01252 KvpValue *retval; 01253 01254 qd = qof_date_parse (content, QOF_DATE_FORMAT_UTC); 01255 if(qd) 01256 { 01257 qt = qof_date_to_qtime (qd); 01258 retval = kvp_value_new_time (qt); 01259 qof_date_free (qd); 01260 qof_time_free (qt); 01261 return retval; 01262 } 01263 else 01264 PERR (" failed to parse date"); 01265 } 01266 #ifndef QOF_DISABLE_DEPRECATED 01267 case KVP_TYPE_TIMESPEC: 01268 { 01269 strptime (content, QSF_XSD_TIME, &kvp_time); 01270 kvp_time_t = mktime (&kvp_time); 01271 timespecFromTime_t (&cm_date, kvp_time_t); 01272 return kvp_value_new_timespec (cm_date); 01273 break; 01274 } 01275 #endif 01276 case KVP_TYPE_BINARY: 01277 // return kvp_value_new_binary(value->value.binary.data, 01278 // value->value.binary.datasize); 01279 break; 01280 case KVP_TYPE_GLIST: 01281 // return kvp_value_new_glist(value->value.list); 01282 break; 01283 case KVP_TYPE_FRAME: 01284 // return kvp_value_new_frame(value->value.frame); 01285 break; 01286 } 01287 return NULL; 01288 } 01289 01290 /* ====================================================== 01291 Commit XML data from file to QofEntity in a QofBook 01292 ========================================================= */ 01293 void 01294 qsf_object_commitCB (gpointer key, gpointer value, gpointer data) 01295 { 01296 qsf_param *params; 01297 qsf_objects *object_set; 01298 xmlNodePtr node; 01299 QofEntityReference *reference; 01300 QofEntity *qsf_ent; 01301 QofBook *targetBook; 01302 const gchar *qof_type, *parameter_name; 01303 QofIdType obj_type, reference_type; 01304 gchar *tail; 01305 /* cm_ prefix used for variables that hold the data to commit */ 01306 QofNumeric cm_numeric; 01307 gdouble cm_double; 01308 gboolean cm_boolean; 01309 gint32 cm_i32; 01310 gint64 cm_i64; 01311 gchar cm_char, (*char_getter) (xmlNodePtr); 01312 GUID *cm_guid; 01313 KvpFrame *cm_kvp; 01314 KvpValue *cm_value; 01315 KvpValueType cm_type; 01316 QofSetterFunc cm_setter; 01317 const QofParam *cm_param; 01318 void (*string_setter) (QofEntity *, const gchar *); 01319 void (*time_setter) (QofEntity *, QofTime *); 01320 void (*numeric_setter) (QofEntity *, QofNumeric); 01321 void (*double_setter) (QofEntity *, gdouble); 01322 void (*boolean_setter) (QofEntity *, gboolean); 01323 void (*i32_setter) (QofEntity *, gint32);