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 | 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... | |
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. | |
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 |
typedef struct QsfMetadata_s | QsfParam |
typedef struct QsfValidates_s | QsfValidator |
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) |
#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 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 180 of file qsf-xml.c.
00181 { 00182 xmlDocPtr doc; 00183 struct QsfNodeIterate qsfiter; 00184 xmlNodePtr object_root; 00185 QsfValidator valid; 00186 gint table_count; 00187 00188 g_return_val_if_fail ((path != NULL), FALSE); 00189 doc = xmlParseFile (path); 00190 if (doc == NULL) 00191 { 00192 return FALSE; 00193 } 00194 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) 00195 { 00196 PINFO (" validation failed %s %s %s", QSF_SCHEMA_DIR, 00197 QSF_OBJECT_SCHEMA, path); 00198 return FALSE; 00199 } 00200 object_root = xmlDocGetRootElement (doc); 00201 /* check that all objects in the file are already registered in QOF */ 00202 valid.object_table = g_hash_table_new (g_str_hash, g_str_equal); 00203 valid.qof_registered_count = 0; 00204 valid.valid_object_count = 0; 00205 qsfiter.ns = object_root->ns; 00206 qsf_valid_foreach (object_root, qsf_object_validation_handler, 00207 &qsfiter, &valid); 00208 table_count = g_hash_table_size (valid.object_table); 00209 g_hash_table_destroy (valid.object_table); 00210 xmlFreeDoc (doc); 00211 if (table_count == valid.qof_registered_count) 00212 { 00213 return TRUE; 00214 } 00215 return FALSE; 00216 }
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 243 of file qsf-xml.c.
00244 { 00245 xmlDocPtr doc; 00246 struct QsfNodeIterate qsfiter; 00247 xmlNodePtr object_root; 00248 QsfValidator valid; 00249 gint table_count; 00250 00251 g_return_val_if_fail ((params != NULL), FALSE); 00252 if (params->filepath == NULL) 00253 { 00254 qof_error_set_be (params->be, qof_error_register 00255 (_("The QSF XML file '%s' could not be found."), TRUE)); 00256 return FALSE; 00257 } 00258 if (params->file_type != QSF_UNDEF) 00259 { 00260 return FALSE; 00261 } 00262 doc = xmlParseFile (params->filepath); 00263 if (doc == NULL) 00264 { 00265 qof_error_set_be (params->be, qof_error_register 00266 (_("There was an error parsing the file '%s'."), TRUE)); 00267 return FALSE; 00268 } 00269 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) 00270 { 00271 qof_error_set_be (params->be, qof_error_register 00272 (_("Invalid QSF Object file! The QSF object file '%s' " 00273 " failed to validate against the QSF object schema. " 00274 "The XML structure of the file is either not well-formed " 00275 "or the file contains illegal data."), TRUE)); 00276 xmlFreeDoc (doc); 00277 return FALSE; 00278 } 00279 params->file_type = IS_QSF_OBJ; 00280 object_root = xmlDocGetRootElement (doc); 00281 xmlFreeDoc (doc); 00282 valid.object_table = g_hash_table_new (g_str_hash, g_str_equal); 00283 valid.qof_registered_count = 0; 00284 qsfiter.ns = object_root->ns; 00285 qsf_valid_foreach (object_root, qsf_object_validation_handler, 00286 &qsfiter, &valid); 00287 table_count = g_hash_table_size (valid.object_table); 00288 if (table_count == valid.qof_registered_count) 00289 { 00290 g_hash_table_destroy (valid.object_table); 00291 return TRUE; 00292 } 00293 g_hash_table_destroy (valid.object_table); 00294 qof_error_set_be (params->be, params->err_nomap); 00295 return FALSE; 00296 }
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 375 of file qsf-xml-map.c.
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)
gboolean is_qsf_map_be | ( | QsfParam * | params | ) |
Validate a QSF map file.
params | Pointer to qsf_param context |
Definition at line 323 of file qsf-xml-map.c.
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)
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 219 of file qsf-xml.c.
00220 { 00221 xmlDocPtr doc; 00222 00223 g_return_val_if_fail ((path != NULL), FALSE); 00224 if (path == NULL) 00225 { 00226 return FALSE; 00227 } 00228 doc = xmlParseFile (path); 00229 if (doc == NULL) 00230 { 00231 return FALSE; 00232 } 00233 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) 00234 { 00235 return FALSE; 00236 } 00237 /* Note cannot test against a map here, so if the file is valid QSF, 00238 accept it and work out the details later. */ 00239 return TRUE; 00240 }
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 299 of file qsf-xml.c.
00300 { 00301 gboolean result; 00302 xmlDocPtr doc; 00303 GList *maps; 00304 gchar *path; 00305 00306 g_return_val_if_fail ((params != NULL), FALSE); 00307 path = g_strdup (params->filepath); 00308 if (path == NULL) 00309 { 00310 qof_error_set_be (params->be, qof_error_register 00311 (_("The QSF XML file '%s' could not be found."), TRUE)); 00312 return FALSE; 00313 } 00314 /* skip validation if is_our_qsf_object has already been called. */ 00315 /* if (ERR_QSF_INVALID_OBJ == qof_backend_get_error (params->be)) 00316 { 00317 return FALSE; 00318 }*/ 00319 if (params->file_type == QSF_UNDEF) 00320 { 00321 doc = xmlParseFile (path); 00322 if (doc == NULL) 00323 { 00324 qof_error_set_be (params->be, qof_error_register 00325 (_("There was an error parsing the file '%s'."), TRUE)); 00326 return FALSE; 00327 } 00328 if (TRUE != qsf_is_valid (QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc)) 00329 { 00330 qof_error_set_be (params->be, qof_error_register 00331 (_("Invalid QSF Object file! The QSF object file '%s' " 00332 " failed to validate against the QSF object schema. " 00333 "The XML structure of the file is either not well-formed " 00334 "or the file contains illegal data."), TRUE)); 00335 return FALSE; 00336 } 00337 } 00338 result = FALSE; 00339 /* retrieve list of maps from config frame. */ 00340 for (maps = params->map_files; maps; maps = maps->next) 00341 { 00342 QofErrorId err; 00343 result = is_qsf_object_with_map_be (maps->data, params); 00344 err = qof_error_check_be (params->be); 00345 if ((err == QOF_SUCCESS) && result) 00346 { 00347 params->map_path = maps->data; 00348 PINFO ("map chosen = %s", params->map_path); 00349 break; 00350 } 00351 } 00352 return result; 00353 }
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 293 of file qsf-xml-map.c.
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)
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 243 of file qsf-xml-map.c.
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)
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 424 of file qsf-xml.c.
00425 { 00426 gchar *book_count_s, *tail; 00427 gint book_count; 00428 xmlNodePtr child_node; 00429 struct QsfNodeIterate qsfiter; 00430 gchar *buffer; 00431 GUID book_guid; 00432 00433 g_return_if_fail (child); 00434 g_return_if_fail (params); 00435 ENTER (" child=%s", child->name); 00436 if (qsf_is_element (child, ns, QSF_BOOK_TAG)) 00437 { 00438 book_count_s = 00439 (gchar *) xmlGetProp (child, BAD_CAST QSF_BOOK_COUNT); 00440 if (book_count_s) 00441 { 00442 book_count = (gint) strtol (book_count_s, &tail, 0); 00443 /* More than one book not currently supported. */ 00444 g_free (book_count_s); 00445 g_return_if_fail (book_count == 1); 00446 } 00447 qsfiter.ns = ns; 00448 child_node = child->children->next; 00449 if (qsf_is_element (child_node, ns, QSF_BOOK_GUID)) 00450 { 00451 DEBUG (" trying to set book GUID"); 00452 buffer = BAD_CAST xmlNodeGetContent (child_node); 00453 g_return_if_fail (TRUE == string_to_guid (buffer, &book_guid)); 00454 qof_entity_set_guid ((QofEntity *) params->book, &book_guid); 00455 xmlNewChild (params->output_node, params->qsf_ns, 00456 BAD_CAST QSF_BOOK_GUID, BAD_CAST buffer); 00457 xmlFree (buffer); 00458 } 00459 qsf_node_foreach (child, qsf_object_node_handler, &qsfiter, params); 00460 } 00461 LEAVE (" "); 00462 }
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 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, | |
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 116 of file qsf-xml.c.
00118 { 00119 xmlNodePtr cur_node; 00120 00121 if (!parent) 00122 return; 00123 g_return_if_fail (params); 00124 g_return_if_fail (qsfiter->ns); 00125 qsfiter->fcn = &cb; 00126 for (cur_node = parent->children; cur_node != NULL; 00127 cur_node = cur_node->next) 00128 { 00129 cb (cur_node, qsfiter->ns, params); 00130 } 00131 }
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 960 of file qsf-xml-map.c.
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 } 01026 }
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 385 of file qsf-xml.c.
00387 { 00388 struct QsfNodeIterate qsfiter; 00389 QsfObject *object_set; 00390 gchar *tail, *object_count_s; 00391 gint64 c; 00392 00393 g_return_if_fail (child != NULL); 00394 g_return_if_fail (qsf_ns != NULL); 00395 params->qsf_ns = qsf_ns; 00396 if (qsf_is_element (child, qsf_ns, QSF_OBJECT_TAG)) 00397 { 00398 params->qsf_parameter_hash = NULL; 00399 c = 0; 00400 object_set = g_new (QsfObject, 1); 00401 params->object_set = object_set; 00402 object_set->object_count = 0; 00403 object_set->parameters = 00404 g_hash_table_new (g_str_hash, g_str_equal); 00405 object_set->object_type = ((gchar *) xmlGetProp (child, 00406 BAD_CAST QSF_OBJECT_TYPE)); 00407 object_count_s = ((gchar *) xmlGetProp (child, 00408 BAD_CAST QSF_OBJECT_COUNT)); 00409 if (object_count_s) 00410 { 00411 c = (gint64) strtol (object_count_s, &tail, 0); 00412 object_set->object_count = (gint) c; 00413 g_free (object_count_s); 00414 } 00415 params->qsf_object_list = 00416 g_list_prepend (params->qsf_object_list, object_set); 00417 qsfiter.ns = qsf_ns; 00418 params->qsf_parameter_hash = object_set->parameters; 00419 qsf_node_foreach (child, qsf_parameter_handler, &qsfiter, params); 00420 } 00421 }
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 134 of file qsf-xml.c.
00136 { 00137 xmlNodePtr cur_node; 00138 xmlChar *object_declaration; 00139 guint count; 00140 QsfStatus type; 00141 gboolean is_registered; 00142 00143 count = 0; 00144 type = QSF_NO_OBJECT; 00145 is_registered = FALSE; 00146 for (cur_node = child->children; cur_node != NULL; 00147 cur_node = cur_node->next) 00148 { 00149 if (qsf_is_element (cur_node, ns, QSF_OBJECT_TAG)) 00150 { 00151 object_declaration = 00152 xmlGetProp (cur_node, BAD_CAST QSF_OBJECT_TYPE); 00153 is_registered = qof_class_is_registered (object_declaration); 00154 if (is_registered) 00155 { 00156 type = QSF_REGISTERED_OBJECT; 00157 } 00158 else 00159 { 00160 type = QSF_DEFINED_OBJECT; 00161 } 00162 xmlFree (object_declaration); 00163 count = g_hash_table_size (valid->object_table); 00164 g_hash_table_insert (valid->object_table, object_declaration, 00165 GINT_TO_POINTER (type)); 00166 /* if insert was successful - i.e. object is unique so far */ 00167 if (g_hash_table_size (valid->object_table) > count) 00168 { 00169 valid->valid_object_count++; 00170 if (is_registered) 00171 { 00172 valid->qof_registered_count++; 00173 } 00174 } 00175 } 00176 } 00177 }
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 102 of file qsf-xml.c.
00104 { 00105 xmlNodePtr cur_node; 00106 00107 qsfiter->v_fcn = &cb; 00108 for (cur_node = parent->children; cur_node != NULL; 00109 cur_node = cur_node->next) 00110 { 00111 cb (cur_node, qsfiter->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 |
Definition at line 1223 of file qsf-backend.c.
01224 { 01225 gchar *tail; 01226 gint64 cm_i64; 01227 gdouble cm_double; 01228 QofNumeric cm_numeric; 01229 GUID *cm_guid; 01230 #ifndef QOF_DISABLE_DEPRECATED 01231 struct tm kvp_time; 01232 time_t kvp_time_t; 01233 Timespec cm_date; 01234 #endif 01235 01236 switch (type) 01237 { 01238 case KVP_TYPE_GINT64: 01239 { 01240 errno = 0; 01241 cm_i64 = strtoll (content, &tail, 0); 01242 if (errno == 0) 01243 { 01244 return kvp_value_new_gint64 (cm_i64); 01245 } 01246 break; 01247 } 01248 case KVP_TYPE_DOUBLE: 01249 { 01250 errno = 0; 01251 cm_double = strtod (content, &tail); 01252 if (errno == 0) 01253 return kvp_value_new_double (cm_double); 01254 break; 01255 } 01256 case KVP_TYPE_NUMERIC: 01257 { 01258 qof_numeric_from_string (content, &cm_numeric); 01259 return kvp_value_new_numeric (cm_numeric); 01260 break; 01261 } 01262 case KVP_TYPE_STRING: 01263 { 01264 return kvp_value_new_string (content); 01265 break; 01266 } 01267 case KVP_TYPE_GUID: 01268 { 01269 cm_guid = g_new0 (GUID, 1); 01270 if (TRUE == string_to_guid (content, cm_guid)) 01271 return kvp_value_new_guid (cm_guid); 01272 break; 01273 } 01274 case KVP_TYPE_TIME : 01275 { 01276 QofDate *qd; 01277 QofTime *qt; 01278 KvpValue *retval; 01279 01280 qd = qof_date_parse (content, QOF_DATE_FORMAT_UTC); 01281 if(qd) 01282 { 01283 qt = qof_date_to_qtime (qd); 01284 retval = kvp_value_new_time (qt); 01285 qof_date_free (qd); 01286 qof_time_free (qt); 01287 return retval; 01288 } 01289 else 01290 PERR (" failed to parse date"); 01291 } 01292 #ifndef QOF_DISABLE_DEPRECATED 01293 case KVP_TYPE_TIMESPEC: 01294 { 01295 strptime (content, QSF_XSD_TIME, &kvp_time); 01296 kvp_time_t = mktime (&kvp_time); 01297 timespecFromTime_t (&cm_date, kvp_time_t); 01298 return kvp_value_new_timespec (cm_date); 01299 break; 01300 } 01301 #endif 01302 case KVP_TYPE_BOOLEAN : 01303 { 01304 gboolean val; 01305 val = qof_util_bool_to_int (content); 01306 return kvp_value_new_boolean (val); 01307 } 01308 case KVP_TYPE_BINARY: 01309 // return kvp_value_new_binary(value->value.binary.data, 01310 // value->value.binary.datasize); 01311 break; 01312 case KVP_TYPE_GLIST: 01313 // return kvp_value_new_glist(value->value.list); 01314 break; 01315 case KVP_TYPE_FRAME: 01316 // return kvp_value_new_frame(value->value.frame); 01317 break; 01318 } 01319 return NULL; 01320 }