|
GnuCash 2.4.99
|
00001 /******************************************************************** 00002 * gnc-transactions-xml-v2.c -- xml routines for transactions * 00003 * Copyright (C) 2001 Rob Browning * 00004 * Copyright (C) 2002 Linas Vepstas <linas@linas.org> * 00005 * * 00006 * This program is free software; you can redistribute it and/or * 00007 * modify it under the terms of the GNU General Public License as * 00008 * published by the Free Software Foundation; either version 2 of * 00009 * the License, or (at your option) any later version. * 00010 * * 00011 * This program is distributed in the hope that it will be useful, * 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00014 * GNU General Public License for more details. * 00015 * * 00016 * You should have received a copy of the GNU General Public License* 00017 * along with this program; if not, contact: * 00018 * * 00019 * Free Software Foundation Voice: +1-617-542-5942 * 00020 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * 00021 * Boston, MA 02110-1301, USA gnu@gnu.org * 00022 * * 00023 *******************************************************************/ 00024 00025 #include "config.h" 00026 00027 #include <glib.h> 00028 #include <string.h> 00029 00030 #include "gnc-xml-helper.h" 00031 00032 #include "sixtp.h" 00033 #include "sixtp-utils.h" 00034 #include "sixtp-parsers.h" 00035 #include "sixtp-utils.h" 00036 #include "sixtp-dom-parsers.h" 00037 #include "sixtp-dom-generators.h" 00038 00039 #include "gnc-xml.h" 00040 00041 #include "io-gncxml-gen.h" 00042 00043 #include "sixtp-dom-parsers.h" 00044 #include "AccountP.h" 00045 #include "Transaction.h" 00046 #include "TransactionP.h" 00047 #include "gnc-lot.h" 00048 #include "gnc-lot-p.h" 00049 00050 const gchar *transaction_version_string = "2.0.0"; 00051 00052 static void 00053 add_gnc_num(xmlNodePtr node, const gchar *tag, gnc_numeric num) 00054 { 00055 xmlAddChild(node, gnc_numeric_to_dom_tree(tag, &num)); 00056 } 00057 00058 static void 00059 add_timespec(xmlNodePtr node, const gchar *tag, Timespec tms, gboolean always) 00060 { 00061 if (always || !((tms.tv_sec == 0) && (tms.tv_nsec == 0))) 00062 { 00063 xmlAddChild(node, timespec_to_dom_tree(tag, &tms)); 00064 } 00065 } 00066 00067 static xmlNodePtr 00068 split_to_dom_tree(const gchar *tag, Split *spl) 00069 { 00070 xmlNodePtr ret; 00071 00072 ret = xmlNewNode(NULL, BAD_CAST tag); 00073 00074 xmlAddChild(ret, guid_to_dom_tree("split:id", xaccSplitGetGUID(spl))); 00075 00076 { 00077 const char *memo = xaccSplitGetMemo(spl); 00078 00079 if (memo && safe_strcmp(memo, "") != 0) 00080 { 00081 xmlNewTextChild(ret, NULL, BAD_CAST "split:memo", (xmlChar*)memo); 00082 } 00083 } 00084 00085 { 00086 const char *action = xaccSplitGetAction(spl); 00087 00088 if (action && safe_strcmp(action, "") != 0) 00089 { 00090 xmlNewTextChild(ret, NULL, BAD_CAST "split:action", (xmlChar*)action); 00091 } 00092 } 00093 00094 { 00095 char tmp[2]; 00096 00097 tmp[0] = xaccSplitGetReconcile(spl); 00098 tmp[1] = '\0'; 00099 00100 xmlNewTextChild(ret, NULL, BAD_CAST "split:reconciled-state", (xmlChar*)tmp); 00101 } 00102 00103 add_timespec(ret, "split:reconcile-date", 00104 xaccSplitRetDateReconciledTS(spl), FALSE); 00105 00106 add_gnc_num(ret, "split:value", xaccSplitGetValue(spl)); 00107 00108 add_gnc_num(ret, "split:quantity", xaccSplitGetAmount(spl)); 00109 00110 { 00111 Account * account = xaccSplitGetAccount (spl); 00112 00113 xmlAddChild (ret, guid_to_dom_tree("split:account", 00114 xaccAccountGetGUID (account))); 00115 } 00116 { 00117 GNCLot * lot = xaccSplitGetLot (spl); 00118 00119 if (lot) 00120 { 00121 xmlAddChild (ret, guid_to_dom_tree("split:lot", 00122 gnc_lot_get_guid(lot))); 00123 } 00124 } 00125 { 00126 xmlNodePtr kvpnode = kvp_frame_to_dom_tree("split:slots", 00127 xaccSplitGetSlots(spl)); 00128 if (kvpnode) 00129 { 00130 xmlAddChild(ret, kvpnode); 00131 } 00132 } 00133 00134 return ret; 00135 } 00136 00137 static void 00138 add_trans_splits(xmlNodePtr node, Transaction *trn) 00139 { 00140 GList *n; 00141 xmlNodePtr toaddto; 00142 00143 toaddto = xmlNewChild(node, NULL, BAD_CAST "trn:splits", NULL); 00144 00145 for (n = xaccTransGetSplitList(trn); n; n = n->next) 00146 { 00147 Split *s = n->data; 00148 xmlAddChild(toaddto, split_to_dom_tree("trn:split", s)); 00149 } 00150 } 00151 00152 xmlNodePtr 00153 gnc_transaction_dom_tree_create(Transaction *trn) 00154 { 00155 xmlNodePtr ret; 00156 00157 ret = xmlNewNode(NULL, BAD_CAST "gnc:transaction"); 00158 00159 xmlSetProp(ret, BAD_CAST "version", BAD_CAST transaction_version_string); 00160 00161 xmlAddChild(ret, guid_to_dom_tree("trn:id", xaccTransGetGUID(trn))); 00162 00163 xmlAddChild(ret, commodity_ref_to_dom_tree("trn:currency", 00164 xaccTransGetCurrency(trn))); 00165 00166 if (xaccTransGetNum(trn) && (safe_strcmp(xaccTransGetNum(trn), "") != 0)) 00167 { 00168 xmlNewTextChild(ret, NULL, BAD_CAST "trn:num", (xmlChar*)xaccTransGetNum(trn)); 00169 } 00170 00171 add_timespec(ret, "trn:date-posted", xaccTransRetDatePostedTS(trn), TRUE); 00172 00173 add_timespec(ret, "trn:date-entered", 00174 xaccTransRetDateEnteredTS(trn), TRUE); 00175 00176 if (xaccTransGetDescription(trn)) 00177 { 00178 xmlNewTextChild(ret, NULL, BAD_CAST "trn:description", 00179 (xmlChar*)xaccTransGetDescription(trn)); 00180 } 00181 00182 { 00183 xmlNodePtr kvpnode = kvp_frame_to_dom_tree("trn:slots", 00184 xaccTransGetSlots(trn)); 00185 if (kvpnode) 00186 { 00187 xmlAddChild(ret, kvpnode); 00188 } 00189 } 00190 00191 add_trans_splits(ret, trn); 00192 00193 return ret; 00194 } 00195 00196 /***********************************************************************/ 00197 00198 struct split_pdata 00199 { 00200 Split *split; 00201 QofBook *book; 00202 }; 00203 00204 static inline gboolean 00205 set_spl_string(xmlNodePtr node, Split *spl, 00206 void (*func)(Split *spl, const char *txt)) 00207 { 00208 gchar *tmp = dom_tree_to_text(node); 00209 g_return_val_if_fail(tmp, FALSE); 00210 00211 func(spl, tmp); 00212 00213 g_free(tmp); 00214 00215 return TRUE; 00216 } 00217 00218 static inline gboolean 00219 set_spl_gnc_num(xmlNodePtr node, Split* spl, 00220 void (*func)(Split *spl, gnc_numeric gn)) 00221 { 00222 gnc_numeric *num = dom_tree_to_gnc_numeric(node); 00223 g_return_val_if_fail(num, FALSE); 00224 00225 func(spl, *num); 00226 00227 g_free(num); 00228 00229 return FALSE; 00230 } 00231 00232 static gboolean 00233 spl_id_handler(xmlNodePtr node, gpointer data) 00234 { 00235 struct split_pdata *pdata = data; 00236 GncGUID *tmp = dom_tree_to_guid(node); 00237 g_return_val_if_fail(tmp, FALSE); 00238 00239 xaccSplitSetGUID(pdata->split, tmp); 00240 00241 g_free(tmp); 00242 return TRUE; 00243 } 00244 00245 static gboolean 00246 spl_memo_handler(xmlNodePtr node, gpointer data) 00247 { 00248 struct split_pdata *pdata = data; 00249 return set_spl_string(node, pdata->split, xaccSplitSetMemo); 00250 } 00251 00252 static gboolean 00253 spl_action_handler(xmlNodePtr node, gpointer data) 00254 { 00255 struct split_pdata *pdata = data; 00256 return set_spl_string(node, pdata->split, xaccSplitSetAction); 00257 } 00258 00259 static gboolean 00260 spl_reconciled_state_handler(xmlNodePtr node, gpointer data) 00261 { 00262 struct split_pdata *pdata = data; 00263 gchar *tmp = dom_tree_to_text(node); 00264 g_return_val_if_fail(tmp, FALSE); 00265 00266 xaccSplitSetReconcile(pdata->split, tmp[0]); 00267 00268 g_free(tmp); 00269 00270 return TRUE; 00271 } 00272 00273 static gboolean 00274 spl_reconcile_date_handler(xmlNodePtr node, gpointer data) 00275 { 00276 struct split_pdata *pdata = data; 00277 Timespec ts; 00278 00279 ts = dom_tree_to_timespec(node); 00280 if (!dom_tree_valid_timespec(&ts, node->name)) return FALSE; 00281 00282 xaccSplitSetDateReconciledTS(pdata->split, &ts); 00283 00284 return TRUE; 00285 } 00286 00287 static gboolean 00288 spl_value_handler(xmlNodePtr node, gpointer data) 00289 { 00290 struct split_pdata *pdata = data; 00291 return set_spl_gnc_num(node, pdata->split, xaccSplitSetValue); 00292 } 00293 00294 static gboolean 00295 spl_quantity_handler(xmlNodePtr node, gpointer data) 00296 { 00297 struct split_pdata *pdata = data; 00298 return set_spl_gnc_num(node, pdata->split, xaccSplitSetAmount); 00299 } 00300 00301 gboolean gnc_transaction_xml_v2_testing = FALSE; 00302 00303 static gboolean 00304 spl_account_handler(xmlNodePtr node, gpointer data) 00305 { 00306 struct split_pdata *pdata = data; 00307 GncGUID *id = dom_tree_to_guid(node); 00308 Account *account; 00309 00310 g_return_val_if_fail(id, FALSE); 00311 00312 account = xaccAccountLookup (id, pdata->book); 00313 if (!account && gnc_transaction_xml_v2_testing && 00314 !guid_equal (id, guid_null ())) 00315 { 00316 account = xaccMallocAccount (pdata->book); 00317 xaccAccountSetGUID (account, id); 00318 xaccAccountSetCommoditySCU (account, 00319 xaccSplitGetAmount (pdata->split).denom); 00320 } 00321 00322 xaccAccountInsertSplit (account, pdata->split); 00323 00324 g_free(id); 00325 00326 return TRUE; 00327 } 00328 00329 static gboolean 00330 spl_lot_handler(xmlNodePtr node, gpointer data) 00331 { 00332 struct split_pdata *pdata = data; 00333 GncGUID *id = dom_tree_to_guid(node); 00334 GNCLot *lot; 00335 00336 g_return_val_if_fail(id, FALSE); 00337 00338 lot = gnc_lot_lookup (id, pdata->book); 00339 if (!lot && gnc_transaction_xml_v2_testing && 00340 !guid_equal (id, guid_null ())) 00341 { 00342 lot = gnc_lot_new (pdata->book); 00343 gnc_lot_set_guid (lot, *id); 00344 } 00345 00346 gnc_lot_add_split (lot, pdata->split); 00347 00348 g_free(id); 00349 00350 return TRUE; 00351 } 00352 00353 static gboolean 00354 spl_slots_handler(xmlNodePtr node, gpointer data) 00355 { 00356 struct split_pdata *pdata = data; 00357 gboolean successful; 00358 00359 successful = dom_tree_to_kvp_frame_given(node, 00360 xaccSplitGetSlots (pdata->split)); 00361 g_return_val_if_fail(successful, FALSE); 00362 00363 return TRUE; 00364 } 00365 00366 struct dom_tree_handler spl_dom_handlers[] = 00367 { 00368 { "split:id", spl_id_handler, 1, 0 }, 00369 { "split:memo", spl_memo_handler, 0, 0 }, 00370 { "split:action", spl_action_handler, 0, 0 }, 00371 { "split:reconciled-state", spl_reconciled_state_handler, 1, 0 }, 00372 { "split:reconcile-date", spl_reconcile_date_handler, 0, 0 }, 00373 { "split:value", spl_value_handler, 1, 0 }, 00374 { "split:quantity", spl_quantity_handler, 1, 0 }, 00375 { "split:account", spl_account_handler, 1, 0 }, 00376 { "split:lot", spl_lot_handler, 0, 0 }, 00377 { "split:slots", spl_slots_handler, 0, 0 }, 00378 { NULL, NULL, 0, 0 }, 00379 }; 00380 00381 static Split* 00382 dom_tree_to_split(xmlNodePtr node, QofBook *book) 00383 { 00384 struct split_pdata pdata; 00385 Split *ret; 00386 00387 g_return_val_if_fail (book, NULL); 00388 00389 ret = xaccMallocSplit(book); 00390 g_return_val_if_fail(ret, NULL); 00391 00392 pdata.split = ret; 00393 pdata.book = book; 00394 00395 /* this isn't going to work in a testing setup */ 00396 if (dom_tree_generic_parse(node, spl_dom_handlers, &pdata)) 00397 { 00398 return ret; 00399 } 00400 else 00401 { 00402 xaccSplitDestroy(ret); 00403 return NULL; 00404 } 00405 } 00406 00407 /***********************************************************************/ 00408 00409 struct trans_pdata 00410 { 00411 Transaction *trans; 00412 QofBook *book; 00413 }; 00414 00415 static inline gboolean 00416 set_tran_string(xmlNodePtr node, Transaction *trn, 00417 void (*func)(Transaction *trn, const char *txt)) 00418 { 00419 gchar *tmp; 00420 00421 tmp = dom_tree_to_text(node); 00422 00423 g_return_val_if_fail(tmp, FALSE); 00424 00425 func(trn, tmp); 00426 00427 g_free(tmp); 00428 00429 return TRUE; 00430 } 00431 00432 static inline gboolean 00433 set_tran_date(xmlNodePtr node, Transaction *trn, 00434 void (*func)(Transaction *trn, const Timespec *tm)) 00435 { 00436 Timespec tm; 00437 00438 tm = dom_tree_to_timespec(node); 00439 00440 if (!dom_tree_valid_timespec(&tm, node->name)) return FALSE; 00441 00442 func(trn, &tm); 00443 00444 return TRUE; 00445 } 00446 00447 static gboolean 00448 trn_id_handler(xmlNodePtr node, gpointer trans_pdata) 00449 { 00450 struct trans_pdata *pdata = trans_pdata; 00451 Transaction *trn = pdata->trans; 00452 GncGUID *tmp = dom_tree_to_guid(node); 00453 00454 g_return_val_if_fail(tmp, FALSE); 00455 00456 xaccTransSetGUID((Transaction*)trn, tmp); 00457 00458 g_free(tmp); 00459 00460 return TRUE; 00461 } 00462 00463 static gboolean 00464 trn_currency_handler(xmlNodePtr node, gpointer trans_pdata) 00465 { 00466 struct trans_pdata *pdata = trans_pdata; 00467 Transaction *trn = pdata->trans; 00468 gnc_commodity *ref; 00469 00470 ref = dom_tree_to_commodity_ref(node, pdata->book); 00471 xaccTransSetCurrency(trn, ref); 00472 00473 return TRUE; 00474 } 00475 00476 static gboolean 00477 trn_num_handler(xmlNodePtr node, gpointer trans_pdata) 00478 { 00479 struct trans_pdata *pdata = trans_pdata; 00480 Transaction *trn = pdata->trans; 00481 00482 return set_tran_string(node, trn, xaccTransSetNum); 00483 } 00484 00485 static gboolean 00486 trn_date_posted_handler(xmlNodePtr node, gpointer trans_pdata) 00487 { 00488 struct trans_pdata *pdata = trans_pdata; 00489 Transaction *trn = pdata->trans; 00490 00491 return set_tran_date(node, trn, xaccTransSetDatePostedTS); 00492 } 00493 00494 static gboolean 00495 trn_date_entered_handler(xmlNodePtr node, gpointer trans_pdata) 00496 { 00497 struct trans_pdata *pdata = trans_pdata; 00498 Transaction *trn = pdata->trans; 00499 00500 return set_tran_date(node, trn, xaccTransSetDateEnteredTS); 00501 } 00502 00503 static gboolean 00504 trn_description_handler(xmlNodePtr node, gpointer trans_pdata) 00505 { 00506 struct trans_pdata *pdata = trans_pdata; 00507 Transaction *trn = pdata->trans; 00508 00509 return set_tran_string(node, trn, xaccTransSetDescription); 00510 } 00511 00512 static gboolean 00513 trn_slots_handler(xmlNodePtr node, gpointer trans_pdata) 00514 { 00515 struct trans_pdata *pdata = trans_pdata; 00516 Transaction *trn = pdata->trans; 00517 gboolean successful; 00518 00519 successful = dom_tree_to_kvp_frame_given(node, xaccTransGetSlots(trn)); 00520 00521 g_return_val_if_fail(successful, FALSE); 00522 00523 return TRUE; 00524 } 00525 00526 static gboolean 00527 trn_splits_handler(xmlNodePtr node, gpointer trans_pdata) 00528 { 00529 struct trans_pdata *pdata = trans_pdata; 00530 Transaction *trn = pdata->trans; 00531 xmlNodePtr mark; 00532 00533 g_return_val_if_fail(node, FALSE); 00534 g_return_val_if_fail(node->xmlChildrenNode, FALSE); 00535 00536 for (mark = node->xmlChildrenNode; mark; mark = mark->next) 00537 { 00538 Split *spl; 00539 00540 if (safe_strcmp("text", (char*)mark->name) == 0) 00541 continue; 00542 00543 if (safe_strcmp("trn:split", (char*)mark->name)) 00544 { 00545 return FALSE; 00546 } 00547 00548 spl = dom_tree_to_split(mark, pdata->book); 00549 00550 if (spl) 00551 { 00552 xaccTransAppendSplit(trn, spl); 00553 } 00554 else 00555 { 00556 return FALSE; 00557 } 00558 } 00559 return TRUE; 00560 } 00561 00562 struct dom_tree_handler trn_dom_handlers[] = 00563 { 00564 { "trn:id", trn_id_handler, 1, 0 }, 00565 { "trn:currency", trn_currency_handler, 0, 0}, 00566 { "trn:num", trn_num_handler, 0, 0 }, 00567 { "trn:date-posted", trn_date_posted_handler, 1, 0 }, 00568 { "trn:date-entered", trn_date_entered_handler, 1, 0 }, 00569 { "trn:description", trn_description_handler, 0, 0 }, 00570 { "trn:slots", trn_slots_handler, 0, 0 }, 00571 { "trn:splits", trn_splits_handler, 1, 0 }, 00572 { NULL, NULL, 0, 0 }, 00573 }; 00574 00575 static gboolean 00576 gnc_transaction_end_handler(gpointer data_for_children, 00577 GSList* data_from_children, GSList* sibling_data, 00578 gpointer parent_data, gpointer global_data, 00579 gpointer *result, const gchar *tag) 00580 { 00581 Transaction *trn = NULL; 00582 gboolean successful = FALSE; 00583 xmlNodePtr tree = (xmlNodePtr)data_for_children; 00584 gxpf_data *gdata = (gxpf_data*)global_data; 00585 00586 if (parent_data) 00587 { 00588 return TRUE; 00589 } 00590 00591 /* OK. For some messed up reason this is getting called again with a 00592 NULL tag. So we ignore those cases */ 00593 if (!tag) 00594 { 00595 return TRUE; 00596 } 00597 00598 g_return_val_if_fail(tree, FALSE); 00599 00600 trn = dom_tree_to_transaction(tree, gdata->bookdata); 00601 if (trn != NULL) 00602 { 00603 gdata->cb(tag, gdata->parsedata, trn); 00604 successful = TRUE; 00605 } 00606 00607 xmlFreeNode(tree); 00608 00609 return trn != NULL; 00610 } 00611 00612 Transaction * 00613 dom_tree_to_transaction( xmlNodePtr node, QofBook *book ) 00614 { 00615 Transaction *trn; 00616 gboolean successful; 00617 struct trans_pdata pdata; 00618 00619 g_return_val_if_fail(node, NULL); 00620 g_return_val_if_fail(book, NULL); 00621 00622 trn = xaccMallocTransaction(book); 00623 g_return_val_if_fail(trn, NULL); 00624 xaccTransBeginEdit(trn); 00625 00626 pdata.trans = trn; 00627 pdata.book = book; 00628 00629 successful = dom_tree_generic_parse(node, trn_dom_handlers, &pdata); 00630 00631 xaccTransCommitEdit(trn); 00632 00633 if ( !successful ) 00634 { 00635 xmlElemDump(stdout, NULL, node); 00636 xaccTransBeginEdit(trn); 00637 xaccTransDestroy(trn); 00638 xaccTransCommitEdit(trn); 00639 trn = NULL; 00640 } 00641 00642 return trn; 00643 } 00644 00645 sixtp* 00646 gnc_transaction_sixtp_parser_create(void) 00647 { 00648 return sixtp_dom_parser_new(gnc_transaction_end_handler, NULL, NULL); 00649 }
1.7.4