#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 | QsfObject_s |
Holds a description of the QofObject. More... | |
struct | QsfMetadata_s |
QSF Parameters. More... | |
struct | QsfValidates_s |
Validation metadata. More... | |
struct | QsfNodeIterate |
One iterator, two typedefs. More... | |
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 struct QsfObject_s | QsfObject |
Holds a description of the QofObject. | |
typedef struct QsfMetadata_s | QsfParam |
QSF Parameters. | |
typedef struct QsfValidates_s | QsfValidator |
Validation metadata. | |
Enumerations | |
enum | QsfType { 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 (QsfParam *params, gchar *qof_type) |
shorthand function | |
void | qsf_object_validation_handler (xmlNodePtr child, xmlNsPtr ns, QsfValidator *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, QsfParam *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, QsfValidCB cb, struct QsfNodeIterate *qsfiter, QsfValidator *valid) |
void | qsf_node_foreach (xmlNodePtr parent, QsfNodeCB cb, struct QsfNodeIterate *qsfiter, QsfParam *params) |
xmlDocPtr | qsf_object_convert (xmlDocPtr mapDoc, xmlNodePtr qsf_root, QsfParam *params) |
Convert between QSF objects. | |
void | qsf_object_node_handler (xmlNodePtr child, xmlNsPtr qsf_ns, QsfParam *params) |
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(* | QsfNodeCB )(xmlNodePtr, xmlNsPtr, QsfParam *) |
map and qsf object callback | |
typedef void(* | QsfValidCB )(xmlNodePtr, xmlNsPtr, QsfValidator *) |
validator callback | |
gboolean | is_qsf_object_be (QsfParam *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 (QsfParam *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 (QsfParam *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, QsfParam *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. |
Definition in file qsf-xml.h.
#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.
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 QsfObject_s QsfObject |
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 QsfMetadata_s QsfParam |
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 QsfValidates_s QsfValidator |
Validation metadata.
The validation is a separate parse with separate data. This is used to determine which backend should load the data.
typedef void(* QsfValidCB)(xmlNodePtr, xmlNsPtr, QsfValidator *) |
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 443 of file qsf-xml.h.
00444 { 00446 QSF_NO_OBJECT = 0, 00450 QSF_DEFINED_OBJECT, 00453 QSF_REGISTERED_OBJECT, 00455 QSF_CALCULATED_OBJECT, 00457 QSF_INVALID_OBJECT 00458 } QsfStatus;
enum QsfType |
Definition at line 41 of file qsf-xml.h.
00042 { 00044 QSF_UNDEF = 0, 00046 IS_QSF_MAP, 00048 IS_QSF_OBJ, 00050 HAVE_QSF_MAP, 00052 OUR_QSF_OBJ, 00053 } QsfType;
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 application without the need for a QSF map.
Definition at line 179 of file qsf-xml.c.
00180 { 00181 xmlDocPtr doc; 00182 struct QsfNodeIterate qsfiter; 00183 xmlNodePtr object_root; 00184 QsfValidator valid; 00185 gint table_count; 00186 00187 g_return_val_if_fail ((path != NULL), FALSE); 00188 doc = xmlParseFile (path); 00189 if (doc == NULL) 00190 { 00191 return FALSE; 00192 } 00193 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) 00194 { 00195 PINFO (" validation failed %s %s %s", QSF_SCHEMA_DIR, 00196 QSF_OBJECT_SCHEMA, path); 00197 return FALSE; 00198 } 00199 object_root = xmlDocGetRootElement (doc); 00200 /* check that all objects in the file are already registered in QOF */ 00201 valid.object_table = g_hash_table_new (g_str_hash, g_str_equal); 00202 valid.qof_registered_count = 0; 00203 valid.valid_object_count = 0; 00204 qsfiter.ns = object_root->ns; 00205 qsf_valid_foreach (object_root, qsf_object_validation_handler, 00206 &qsfiter, &valid); 00207 table_count = g_hash_table_size (valid.object_table); 00208 g_hash_table_destroy (valid.object_table); 00209 xmlFreeDoc (doc); 00210 if (table_count == valid.qof_registered_count) 00211 { 00212 return TRUE; 00213 } 00214 return FALSE; 00215 }
gboolean is_our_qsf_object_be | ( | QsfParam * | 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.
Definition at line 242 of file qsf-xml.c.
00243 { 00244 xmlDocPtr doc; 00245 struct QsfNodeIterate qsfiter; 00246 xmlNodePtr object_root; 00247 QsfValidator valid; 00248 gint table_count; 00249 00250 g_return_val_if_fail ((params != NULL), FALSE); 00251 if (params->filepath == NULL) 00252 { 00253 qof_error_set_be (params->be, qof_error_register 00254 (_("The QSF XML file '%s' could not be found."), TRUE)); 00255 return FALSE; 00256 } 00257 if (params->file_type != QSF_UNDEF) 00258 { 00259 return FALSE; 00260 } 00261 doc = xmlParseFile (params->filepath); 00262 if (doc == NULL) 00263 { 00264 qof_error_set_be (params->be, qof_error_register 00265 (_("There was an error parsing the file '%s'."), TRUE)); 00266 return FALSE; 00267 } 00268 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) 00269 { 00270 qof_error_set_be (params->be, qof_error_register 00271 (_("Invalid QSF Object file! The QSF object file '%s' " 00272 " failed to validate against the QSF object schema. " 00273 "The XML structure of the file is either not well-formed " 00274 "or the file contains illegal data."), TRUE)); 00275 xmlFreeDoc (doc); 00276 return FALSE; 00277 } 00278 params->file_type = IS_QSF_OBJ; 00279 object_root = xmlDocGetRootElement (doc); 00280 xmlFreeDoc (doc); 00281 valid.object_table = g_hash_table_new (g_str_hash, g_str_equal); 00282 valid.qof_registered_count = 0; 00283 qsfiter.ns = object_root->ns; 00284 qsf_valid_foreach (object_root, qsf_object_validation_handler, 00285 &qsfiter, &valid); 00286 table_count = g_hash_table_size (valid.object_table); 00287 if (table_count == valid.qof_registered_count) 00288 { 00289 g_hash_table_destroy (valid.object_table); 00290 return TRUE; 00291 } 00292 g_hash_table_destroy (valid.object_table); 00293 qof_error_set_be (params->be, params->err_nomap); 00294 return FALSE; 00295 }
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.
Definition at line 371 of file qsf-xml-map.c.
00372 { 00373 xmlDocPtr doc; 00374 struct QsfNodeIterate qsfiter; 00375 QsfValidator valid; 00376 xmlNodePtr map_root; 00377 xmlNsPtr map_ns; 00378 00379 g_return_val_if_fail ((path != NULL), FALSE); 00380 if (path == NULL) 00381 { 00382 return FALSE; 00383 } 00384 doc = xmlParseFile (path); 00385 if (doc == NULL) 00386 { 00387 return FALSE; 00388 } 00389 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_MAP_SCHEMA, doc)) 00390 { 00391 return FALSE; 00392 } 00393 map_root = xmlDocGetRootElement (doc); 00394 map_ns = map_root->ns; 00395 qsfiter.ns = map_ns; 00396 valid.error_state = QOF_SUCCESS; 00397 valid.map_table = g_hash_table_new (g_str_hash, g_str_equal); 00398 qsf_valid_foreach (map_root, qsf_map_validation_handler, 00399 &qsfiter, &valid); 00400 if (valid.error_state != QOF_SUCCESS) 00401 { 00402 g_hash_table_destroy (valid.map_table); 00403 return FALSE; 00404 } 00405 g_hash_table_destroy (valid.map_table); 00406 return TRUE; 00407 }
gboolean is_qsf_map_be | ( | QsfParam * | params | ) |
Validate a QSF map file.
params | Pointer to qsf_param context |
Definition at line 319 of file qsf-xml-map.c.
00320 { 00321 xmlDocPtr doc; 00322 struct QsfNodeIterate qsfiter; 00323 QsfValidator valid; 00324 xmlNodePtr map_root; 00325 xmlNsPtr map_ns; 00326 gchar *path; 00327 00328 g_return_val_if_fail ((params != NULL), FALSE); 00329 path = g_strdup (params->filepath); 00330 if (path == NULL) 00331 { 00332 qof_error_set_be (params->be, qof_error_register 00333 (_("The QSF XML file '%s' could not be found."), TRUE)); 00334 return FALSE; 00335 } 00336 doc = xmlParseFile (path); 00337 if (doc == NULL) 00338 { 00339 qof_error_set_be (params->be, qof_error_register 00340 (_("There was an error parsing the file '%s'."), TRUE)); 00341 return FALSE; 00342 } 00343 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_MAP_SCHEMA, doc)) 00344 { 00345 qof_error_set_be (params->be, 00346 qof_error_register ( 00347 _("Invalid QSF Map file! The QSF map file " 00348 "failed to validate against the QSF map schema. " 00349 "The XML structure of the file is either not well-formed " 00350 "or the file contains illegal data."), FALSE)); 00351 return FALSE; 00352 } 00353 map_root = xmlDocGetRootElement (doc); 00354 map_ns = map_root->ns; 00355 qsfiter.ns = map_ns; 00356 valid.object_table = g_hash_table_new (g_str_hash, g_str_equal); 00357 valid.map_table = g_hash_table_new (g_str_hash, g_str_equal); 00358 valid.error_state = QOF_SUCCESS; 00359 qsf_valid_foreach (map_root, qsf_map_validation_handler, 00360 &qsfiter, &valid); 00361 if (valid.error_state != QOF_SUCCESS) 00362 { 00363 g_hash_table_destroy (valid.object_table); 00364 return FALSE; 00365 } 00366 g_hash_table_destroy (valid.object_table); 00367 return TRUE; 00368 }
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.
Definition at line 218 of file qsf-xml.c.
00219 { 00220 xmlDocPtr doc; 00221 00222 g_return_val_if_fail ((path != NULL), FALSE); 00223 if (path == NULL) 00224 { 00225 return FALSE; 00226 } 00227 doc = xmlParseFile (path); 00228 if (doc == NULL) 00229 { 00230 return FALSE; 00231 } 00232 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) 00233 { 00234 return FALSE; 00235 } 00236 /* Note cannot test against a map here, so if the file is valid QSF, 00237 accept it and work out the details later. */ 00238 return TRUE; 00239 }
gboolean is_qsf_object_be | ( | QsfParam * | 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.
Definition at line 298 of file qsf-xml.c.
00299 { 00300 gboolean result; 00301 xmlDocPtr doc; 00302 GList *maps; 00303 gchar *path; 00304 00305 g_return_val_if_fail ((params != NULL), FALSE); 00306 path = g_strdup (params->filepath); 00307 if (path == NULL) 00308 { 00309 qof_error_set_be (params->be, qof_error_register 00310 (_("The QSF XML file '%s' could not be found."), TRUE)); 00311 return FALSE; 00312 } 00313 /* skip validation if is_our_qsf_object has already been called. */ 00314 /* if (ERR_QSF_INVALID_OBJ == qof_backend_get_error (params->be)) 00315 { 00316 return FALSE; 00317 }*/ 00318 if (params->file_type == QSF_UNDEF) 00319 { 00320 doc = xmlParseFile (path); 00321 if (doc == NULL) 00322 { 00323 qof_error_set_be (params->be, qof_error_register 00324 (_("There was an error parsing the file '%s'."), TRUE)); 00325 return FALSE; 00326 } 00327 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) 00328 { 00329 qof_error_set_be (params->be, qof_error_register 00330 (_("Invalid QSF Object file! The QSF object file '%s' " 00331 " failed to validate against the QSF object schema. " 00332 "The XML structure of the file is either not well-formed " 00333 "or the file contains illegal data."), TRUE)); 00334 return FALSE; 00335 } 00336 } 00337 result = FALSE; 00338 /* retrieve list of maps from config frame. */ 00339 for (maps = params->map_files; maps; maps = maps->next) 00340 { 00341 QofErrorId err; 00342 result = is_qsf_object_with_map_be (maps->data, params); 00343 err = qof_error_check_be (params->be); 00344 if ((err == QOF_SUCCESS) && result) 00345 { 00346 params->map_path = maps->data; 00347 PINFO ("map chosen = %s", params->map_path); 00348 break; 00349 } 00350 } 00351 return result; 00352 }
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. |
Definition at line 289 of file qsf-xml-map.c.
00290 { 00291 xmlDocPtr doc, map_doc; 00292 QofErrorId result; 00293 gchar *map_path; 00294 00295 map_path = g_strdup_printf ("%s/%s", QSF_SCHEMA_DIR, map_file); 00296 if (path == NULL) 00297 { 00298 return FALSE; 00299 } 00300 doc = xmlParseFile (path); 00301 if (doc == NULL) 00302 { 00303 return FALSE; 00304 } 00305 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) 00306 { 00307 return FALSE; 00308 } 00309 if (map_path == NULL) 00310 { 00311 return FALSE; 00312 } 00313 map_doc = xmlParseFile (map_path); 00314 result = check_qsf_object_with_map_internal (map_doc, doc); 00315 return (result == QOF_SUCCESS) ? TRUE : FALSE; 00316 }
gboolean is_qsf_object_with_map_be | ( | gchar * | map_path, | |
QsfParam * | 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 QofErrorId codes.
Definition at line 239 of file qsf-xml-map.c.
00240 { 00241 xmlDocPtr doc, map_doc; 00242 QofErrorId result; 00243 gchar *path, *map_path; 00244 00245 g_return_val_if_fail ((params != NULL), FALSE); 00246 path = g_strdup (params->filepath); 00247 map_path = g_strdup_printf ("%s/%s", QSF_SCHEMA_DIR, map_file); 00248 PINFO (" checking map file '%s'", map_path); 00249 if (path == NULL) 00250 { 00251 qof_error_set_be (params->be, qof_error_register 00252 (_("The QSF XML file '%s' could not be found."), TRUE)); 00253 return FALSE; 00254 } 00255 doc = xmlParseFile (path); 00256 if (doc == NULL) 00257 { 00258 qof_error_set_be (params->be, qof_error_register 00259 (_("There was an error parsing the file '%s'."), TRUE)); 00260 return FALSE; 00261 } 00262 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) 00263 { 00264 qof_error_set_be (params->be, qof_error_register 00265 (_("Invalid QSF Object file! The QSF object file '%s' " 00266 " failed to validate against the QSF object schema. " 00267 "The XML structure of the file is either not well-formed " 00268 "or the file contains illegal data."), TRUE)); 00269 return FALSE; 00270 } 00271 if (map_path == NULL) 00272 { 00273 qof_error_set_be (params->be, qof_error_register 00274 (_("The QSF map file '%s' could not be found."), TRUE)); 00275 return FALSE; 00276 } 00277 map_doc = xmlParseFile (map_path); 00278 if (map_doc == NULL) 00279 { 00280 qof_error_set_be (params->be, qof_error_register 00281 (_("There was an error parsing the file '%s'."), TRUE)); 00282 return FALSE; 00283 } 00284 result = check_qsf_object_with_map_internal (map_doc, doc); 00285 return (result == QOF_SUCCESS) ? TRUE : FALSE; 00286 }
void qsf_book_node_handler | ( | xmlNodePtr | child, | |
xmlNsPtr | qsf_ns, | |||
QsfParam * | 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.
Definition at line 423 of file qsf-xml.c.
00424 { 00425 gchar *book_count_s, *tail; 00426 gint book_count; 00427 xmlNodePtr child_node; 00428 struct QsfNodeIterate qsfiter; 00429 gchar *buffer; 00430 GUID book_guid; 00431 00432 g_return_if_fail (child); 00433 g_return_if_fail (params); 00434 ENTER (" child=%s", child->name); 00435 if (qsf_is_element (child, ns, QSF_BOOK_TAG)) 00436 { 00437 book_count_s = 00438 (gchar *) xmlGetProp (child, BAD_CAST QSF_BOOK_COUNT); 00439 if (book_count_s) 00440 { 00441 book_count = (gint) strtol (book_count_s, &tail, 0); 00442 /* More than one book not currently supported. */ 00443 g_free (book_count_s); 00444 g_return_if_fail (book_count == 1); 00445 } 00446 qsfiter.ns = ns; 00447 child_node = child->children->next; 00448 if (qsf_is_element (child_node, ns, QSF_BOOK_GUID)) 00449 { 00450 DEBUG (" trying to set book GUID"); 00451 buffer = (gchar*) xmlNodeGetContent (child_node); 00452 g_return_if_fail (TRUE == string_to_guid (buffer, &book_guid)); 00453 qof_entity_set_guid ((QofEntity *) params->book, &book_guid); 00454 xmlNewChild (params->output_node, params->qsf_ns, 00455 BAD_CAST QSF_BOOK_GUID, BAD_CAST buffer); 00456 xmlFree (buffer); 00457 } 00458 qsf_node_foreach (child, qsf_object_node_handler, &qsfiter, params); 00459 } 00460 LEAVE (" "); 00461 }
gint qsf_check_tag | ( | QsfParam * | 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 68 of file qsf-xml.c.
00069 { 00070 return qsf_is_element (params->child_node, params->qsf_ns, qof_type); 00071 }
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 54 of file qsf-xml.c.
00055 { 00056 g_return_val_if_fail (a != NULL, 0); 00057 g_return_val_if_fail (ns != NULL, 0); 00058 g_return_val_if_fail (c != NULL, 0); 00059 if ((a->ns == ns) && (a->type == XML_ELEMENT_NODE) && 00060 qsf_strings_equal (a->name, c)) 00061 { 00062 return 1; 00063 } 00064 return 0; 00065 }
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 74 of file qsf-xml.c.
00076 { 00077 xmlSchemaParserCtxtPtr qsf_schema_file; 00078 xmlSchemaPtr qsf_schema; 00079 xmlSchemaValidCtxtPtr qsf_context; 00080 gchar *schema_path; 00081 gint result; 00082 00083 g_return_val_if_fail (doc || schema_filename, FALSE); 00084 schema_path = g_strdup_printf ("%s/%s", schema_dir, schema_filename); 00085 qsf_schema_file = xmlSchemaNewParserCtxt (schema_path); 00086 qsf_schema = xmlSchemaParse (qsf_schema_file); 00087 qsf_context = xmlSchemaNewValidCtxt (qsf_schema); 00088 result = xmlSchemaValidateDoc (qsf_context, doc); 00089 xmlSchemaFreeParserCtxt (qsf_schema_file); 00090 xmlSchemaFreeValidCtxt (qsf_context); 00091 xmlSchemaFree (qsf_schema); 00092 g_free (schema_path); 00093 if (result == 0) 00094 { 00095 return TRUE; 00096 } 00097 return FALSE; 00098 }
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, | |
QsfNodeCB | cb, | |||
struct QsfNodeIterate * | qsfiter, | |||
QsfParam * | 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 115 of file qsf-xml.c.
00117 { 00118 xmlNodePtr cur_node; 00119 00120 if (!parent) 00121 return; 00122 g_return_if_fail (params); 00123 g_return_if_fail (qsfiter->ns); 00124 qsfiter->fcn = &cb; 00125 for (cur_node = parent->children; cur_node != NULL; 00126 cur_node = cur_node->next) 00127 { 00128 cb (cur_node, qsfiter->ns, params); 00129 } 00130 }
xmlDocPtr qsf_object_convert | ( | xmlDocPtr | mapDoc, | |
xmlNodePtr | qsf_root, | |||
QsfParam * | 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. |
Definition at line 953 of file qsf-xml-map.c.
00955 { 00956 /* mapDoc : map document. qsf_root: incoming QSF root node. */ 00957 struct QsfNodeIterate qsfiter; 00958 xmlDocPtr output_doc; 00959 xmlNode *cur_node; 00960 xmlNode *map_root, *output_root; 00961 00962 g_return_val_if_fail ((mapDoc && qsf_root && params), NULL); 00963 ENTER (" root=%s", qsf_root->name); 00964 /* prepare the intermediary document */ 00965 qsfiter.ns = params->qsf_ns; 00966 output_doc = xmlNewDoc (BAD_CAST QSF_XML_VERSION); 00967 output_root = xmlNewNode (NULL, BAD_CAST QSF_ROOT_TAG); 00968 xmlDocSetRootElement (output_doc, output_root); 00969 xmlSetNs (output_root, params->qsf_ns); 00970 params->output_node = xmlNewChild (output_root, params->qsf_ns, 00971 BAD_CAST QSF_BOOK_TAG, NULL); 00972 xmlNewProp (params->output_node, BAD_CAST QSF_BOOK_COUNT, 00973 BAD_CAST "1"); 00974 /* parse the incoming QSF */ 00975 qsf_book_node_handler (qsf_root->children->next, params->qsf_ns, 00976 params); 00977 /* parse the map and calculate the values */ 00978 map_root = xmlDocGetRootElement (mapDoc); 00979 params->foreach_limit = 0; 00980 qsfiter.ns = params->map_ns; 00981 /* sets qof_foreach iterator, defines and defaults. */ 00982 qsf_node_foreach (map_root, qsf_map_top_node_handler, &qsfiter, params); 00983 /* identify the entities of iterator type. */ 00984 qsfiter.ns = params->qsf_ns; 00985 qsf_node_foreach (qsf_root->children->next, iterator_cb, &qsfiter, 00986 params); 00987 PINFO (" counted %d records", params->foreach_limit); 00988 params->count = 0; 00989 for (cur_node = map_root->children; cur_node != NULL; 00990 cur_node = cur_node->next) 00991 { 00992 params->convert_node = cur_node; 00993 if (qsf_is_element (cur_node, params->map_ns, MAP_OBJECT_TAG)) 00994 { 00995 gint i; 00996 00997 params->lister = NULL; 00998 PINFO (" found an object tag. starting calculation"); 00999 /* cur_node describes the target object */ 01000 if (!qof_class_is_registered ((gchar*) 01001 xmlGetProp (cur_node, BAD_CAST MAP_TYPE_ATTR))) 01002 { 01003 continue; 01004 } 01005 qsf_add_object_tag (params, params->count); 01006 params->count++; 01007 qsfiter.ns = params->map_ns; 01008 PINFO (" params->foreach_limit=%d", params->foreach_limit); 01009 for (i = -1; i < params->foreach_limit; i++) 01010 { 01011 qsf_node_foreach (cur_node, qsf_map_object_handler, 01012 &qsfiter, params); 01013 params->qsf_object_list = 01014 g_list_next (params->qsf_object_list); 01015 params->count++; 01016 } 01017 } 01018 } 01019 params->file_type = OUR_QSF_OBJ; 01020 /* use for debugging */ 01021 xmlSaveFormatFileEnc ("-", output_doc, "UTF-8", 1); 01022 LEAVE (" "); 01023 return output_doc; 01024 }
void qsf_object_node_handler | ( | xmlNodePtr | child, | |
xmlNsPtr | qsf_ns, | |||
QsfParam * | params | |||
) |
Despite the name, this function handles the QSF object book tag AND the object tags.
Used to parse object and map files.
Definition at line 384 of file qsf-xml.c.
00386 { 00387 struct QsfNodeIterate qsfiter; 00388 QsfObject *object_set; 00389 gchar *tail, *object_count_s; 00390 gint64 c; 00391 00392 g_return_if_fail (child != NULL); 00393 g_return_if_fail (qsf_ns != NULL); 00394 params->qsf_ns = qsf_ns; 00395 if (qsf_is_element (child, qsf_ns, QSF_OBJECT_TAG)) 00396 { 00397 params->qsf_parameter_hash = NULL; 00398 c = 0; 00399 object_set = g_new (QsfObject, 1); 00400 params->object_set = object_set; 00401 object_set->object_count = 0; 00402 object_set->parameters = 00403 g_hash_table_new (g_str_hash, g_str_equal); 00404 object_set->object_type = ((gchar *) xmlGetProp (child, 00405 BAD_CAST QSF_OBJECT_TYPE)); 00406 object_count_s = ((gchar *) xmlGetProp (child, 00407 BAD_CAST QSF_OBJECT_COUNT)); 00408 if (object_count_s) 00409 { 00410 c = (gint64) strtol (object_count_s, &tail, 0); 00411 object_set->object_count = (gint) c; 00412 g_free (object_count_s); 00413 } 00414 params->qsf_object_list = 00415 g_list_prepend (params->qsf_object_list, object_set); 00416 qsfiter.ns = qsf_ns; 00417 params->qsf_parameter_hash = object_set->parameters; 00418 qsf_node_foreach (child, qsf_parameter_handler, &qsfiter, params); 00419 } 00420 }
void qsf_object_validation_handler | ( | xmlNodePtr | child, | |
xmlNsPtr | ns, | |||
QsfValidator * | 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.
Definition at line 133 of file qsf-xml.c.
00135 { 00136 xmlNodePtr cur_node; 00137 xmlChar *object_declaration; 00138 guint count; 00139 QsfStatus type; 00140 gboolean is_registered; 00141 00142 count = 0; 00143 type = QSF_NO_OBJECT; 00144 is_registered = FALSE; 00145 for (cur_node = child->children; cur_node != NULL; 00146 cur_node = cur_node->next) 00147 { 00148 if (qsf_is_element (cur_node, ns, QSF_OBJECT_TAG)) 00149 { 00150 object_declaration = 00151 xmlGetProp (cur_node, BAD_CAST QSF_OBJECT_TYPE); 00152 is_registered = qof_class_is_registered ((gchar*)object_declaration); 00153 if (is_registered) 00154 { 00155 type = QSF_REGISTERED_OBJECT; 00156 } 00157 else 00158 { 00159 type = QSF_DEFINED_OBJECT; 00160 } 00161 xmlFree (object_declaration); 00162 count = g_hash_table_size (valid->object_table); 00163 g_hash_table_insert (valid->object_table, object_declaration, 00164 GINT_TO_POINTER (type)); 00165 /* if insert was successful - i.e. object is unique so far */ 00166 if (g_hash_table_size (valid->object_table) > count) 00167 { 00168 valid->valid_object_count++; 00169 if (is_registered) 00170 { 00171 valid->qof_registered_count++; 00172 } 00173 } 00174 } 00175 } 00176 }
gint qsf_strings_equal | ( | const xmlChar * | node_name, | |
gchar * | tag_name | |||
) |
void qsf_valid_foreach | ( | xmlNodePtr | parent, | |
QsfValidCB | cb, | |||
struct QsfNodeIterate * | qsfiter, | |||
QsfValidator * | valid | |||
) |
Validate the children of the parent node.
Definition at line 101 of file qsf-xml.c.
00103 { 00104 xmlNodePtr cur_node; 00105 00106 qsfiter->v_fcn = &cb; 00107 for (cur_node = parent->children; cur_node != NULL; 00108 cur_node = cur_node->next) 00109 { 00110 cb (cur_node, qsfiter->ns, valid); 00111 } 00112 }
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 |
Definition at line 1164 of file qsf-backend.c.
01165 { 01166 gchar *tail; 01167 gint64 cm_i64; 01168 gdouble cm_double; 01169 QofNumeric cm_numeric; 01170 GUID *cm_guid; 01171 01172 switch (type) 01173 { 01174 case KVP_TYPE_GINT64: 01175 { 01176 errno = 0; 01177 cm_i64 = strtoll (content, &tail, 0); 01178 if (errno == 0) 01179 { 01180 return kvp_value_new_gint64 (cm_i64); 01181 } 01182 break; 01183 } 01184 case KVP_TYPE_DOUBLE: 01185 { 01186 errno = 0; 01187 cm_double = strtod (content, &tail); 01188 if (errno == 0) 01189 return kvp_value_new_double (cm_double); 01190 break; 01191 } 01192 case KVP_TYPE_NUMERIC: 01193 { 01194 qof_numeric_from_string (content, &cm_numeric); 01195 return kvp_value_new_numeric (cm_numeric); 01196 break; 01197 } 01198 case KVP_TYPE_STRING: 01199 { 01200 return kvp_value_new_string (content); 01201 break; 01202 } 01203 case KVP_TYPE_GUID: 01204 { 01205 cm_guid = g_new0 (GUID, 1); 01206 if (TRUE == string_to_guid (content, cm_guid)) 01207 return kvp_value_new_guid (cm_guid); 01208 break; 01209 } 01210 case KVP_TYPE_TIME : 01211 { 01212 QofDate *qd; 01213 QofTime *qt; 01214 KvpValue *retval; 01215 01216 qd = qof_date_parse (content, QOF_DATE_FORMAT_UTC); 01217 if(qd) 01218 { 01219 qt = qof_date_to_qtime (qd); 01220 retval = kvp_value_new_time (qt); 01221 qof_date_free (qd); 01222 qof_time_free (qt); 01223 return retval; 01224 } 01225 else 01226 PERR (" failed to parse date"); 01227 } 01228 case KVP_TYPE_BOOLEAN : 01229 { 01230 gboolean val; 01231 val = qof_util_bool_to_int (content); 01232 return kvp_value_new_boolean (val); 01233 } 01234 case KVP_TYPE_BINARY: 01235 // return kvp_value_new_binary(value->value.binary.data, 01236 // value->value.binary.datasize); 01237 break; 01238 case KVP_TYPE_GLIST: 01239 // return kvp_value_new_glist(value->value.list); 01240 break; 01241 case KVP_TYPE_FRAME: 01242 // return kvp_value_new_frame(value->value.frame); 01243 break; 01244 } 01245 return NULL; 01246 }