gnc-account-xml-v2.c

00001 /********************************************************************\
00002  * gnc-account-xml-v2.c -- account xml i/o implementation           *
00003  *                                                                  *
00004  * Copyright (C) 2001 James LewisMoss <dres@debian.org>             *
00005  * Copyright (C) 2002 Linas Vepstas <linas@linas.org>               *
00006  *                                                                  *
00007  * This program is free software; you can redistribute it and/or    *
00008  * modify it under the terms of the GNU General Public License as   *
00009  * published by the Free Software Foundation; either version 2 of   *
00010  * the License, or (at your option) any later version.              *
00011  *                                                                  *
00012  * This program is distributed in the hope that it will be useful,  *
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00015  * GNU General Public License for more details.                     *
00016  *                                                                  *
00017  * You should have received a copy of the GNU General Public License*
00018  * along with this program; if not, contact:                        *
00019  *                                                                  *
00020  * Free Software Foundation           Voice:  +1-617-542-5942       *
00021  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
00022  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
00023  *                                                                  *
00024 \********************************************************************/
00025 
00026 #include "config.h"
00027 
00028 #include <glib.h>
00029 #include <stdlib.h>
00030 #include <string.h>
00031 
00032 #include "gnc-xml-helper.h"
00033 #include "sixtp.h"
00034 #include "sixtp-utils.h"
00035 #include "sixtp-parsers.h"
00036 #include "sixtp-utils.h"
00037 #include "sixtp-dom-parsers.h"
00038 #include "sixtp-dom-generators.h"
00039 
00040 #include "gnc-xml.h"
00041 #include "io-gncxml-gen.h"
00042 #include "io-gncxml-v2.h"
00043 
00044 #include "sixtp-dom-parsers.h"
00045 #include "AccountP.h"
00046 #include "Account.h"
00047 
00048 static QofLogModule log_module = GNC_MOD_IO;
00049 
00050 const gchar *account_version_string = "2.0.0";
00051 
00052 /* ids */
00053 #define gnc_account_string "gnc:account"
00054 #define act_name_string "act:name"
00055 #define act_id_string "act:id"
00056 #define act_type_string "act:type"
00057 #define act_commodity_string "act:commodity"
00058 #define act_commodity_scu_string "act:commodity-scu"
00059 #define act_non_standard_scu_string "act:non-standard-scu"
00060 #define act_code_string "act:code"
00061 #define act_description_string "act:description"
00062 #define act_slots_string "act:slots"
00063 #define act_parent_string "act:parent"
00064 #define act_lots_string "act:lots"
00065 /* The currency and security strings should not appear in newer
00066  * xml files (anything post-gnucash-1.6) */
00067 #define act_currency_string "act:currency"
00068 #define act_currency_scu_string "act:currency-scu"
00069 #define act_security_string "act:security"
00070 #define act_security_scu_string "act:security-scu"
00071 
00072 xmlNodePtr
00073 gnc_account_dom_tree_create(Account *act,
00074                             gboolean exporting,
00075                             gboolean allow_incompat)
00076 {
00077     const char *str;
00078     kvp_frame *kf;
00079     xmlNodePtr ret;
00080     GList *lots, *n;
00081     Account *parent;
00082 
00083     ENTER ("(account=%p)", act);
00084 
00085     ret = xmlNewNode(NULL, BAD_CAST gnc_account_string);
00086     xmlSetProp(ret, BAD_CAST "version", BAD_CAST account_version_string);
00087 
00088     xmlAddChild(ret, text_to_dom_tree(act_name_string,
00089                                       xaccAccountGetName(act)));
00090     
00091     xmlAddChild(ret, guid_to_dom_tree(act_id_string, xaccAccountGetGUID(act)));
00092 
00093     xmlAddChild(ret, text_to_dom_tree(
00094                     act_type_string,
00095                     xaccAccountTypeEnumAsString(xaccAccountGetType(act))));
00096 
00097     xmlAddChild(ret, commodity_ref_to_dom_tree(act_commodity_string,
00098                                                xaccAccountGetCommodity(act)));
00099 
00100     xmlAddChild(ret, int_to_dom_tree(act_commodity_scu_string,
00101                                      xaccAccountGetCommoditySCUi(act)));
00102     
00103     if (xaccAccountGetNonStdSCU(act))
00104       xmlNewChild(ret, NULL, BAD_CAST act_non_standard_scu_string, NULL);
00105     
00106     str = xaccAccountGetCode(act);
00107     if (str && strlen(str) > 0)
00108     {
00109         xmlAddChild(ret, text_to_dom_tree(act_code_string, str));
00110     }
00111 
00112     str = xaccAccountGetDescription(act);
00113     if (str && strlen(str) > 0)
00114     {
00115         xmlAddChild(ret, text_to_dom_tree(act_description_string, str));
00116     }
00117        
00118     kf = xaccAccountGetSlots(act);
00119     if(kf)
00120     {
00121         xmlNodePtr kvpnode = kvp_frame_to_dom_tree(act_slots_string, kf);
00122         if(kvpnode)
00123         {
00124             xmlAddChild(ret, kvpnode);
00125         }
00126     }
00127 
00128     parent = gnc_account_get_parent(act);
00129     if (parent)
00130     {
00131       if (!gnc_account_is_root(parent) || allow_incompat)
00132         xmlAddChild(ret, guid_to_dom_tree(act_parent_string,
00133                                           xaccAccountGetGUID(parent)));
00134     }
00135 
00136     lots = xaccAccountGetLotList (act);
00137     PINFO ("lot list=%p", lots);
00138     if (lots && !exporting)
00139     {
00140        xmlNodePtr toaddto = xmlNewChild(ret, NULL, BAD_CAST act_lots_string, NULL);
00141 
00142        for (n = lots; n; n=n->next)
00143        {
00144           GNCLot * lot = n->data;
00145           xmlAddChild(toaddto, gnc_lot_dom_tree_create(lot));
00146        }
00147     }
00148     g_list_free(lots);
00149 
00150     LEAVE("");
00151     return ret;
00152 }
00153 
00154 /***********************************************************************/
00155 
00156 struct account_pdata
00157 {
00158   Account *account;
00159   QofBook *book;
00160 };
00161 
00162 static inline gboolean
00163 set_string(xmlNodePtr node, Account* act,
00164            void (*func)(Account *act, const gchar *txt))
00165 {
00166     gchar* txt = dom_tree_to_text(node);
00167     g_return_val_if_fail(txt, FALSE);
00168     
00169     func(act, txt);
00170 
00171     g_free(txt);
00172     
00173     return TRUE;
00174 }
00175 
00176 static gboolean
00177 account_name_handler (xmlNodePtr node, gpointer act_pdata)
00178 {
00179     struct account_pdata *pdata = act_pdata;
00180 
00181     return set_string(node, pdata->account, xaccAccountSetName);
00182 }
00183 
00184 static gboolean
00185 account_id_handler (xmlNodePtr node, gpointer act_pdata)
00186 {
00187     struct account_pdata *pdata = act_pdata;
00188     GUID *guid;
00189 
00190     guid = dom_tree_to_guid(node);
00191     g_return_val_if_fail(guid, FALSE);
00192 
00193     xaccAccountSetGUID(pdata->account, guid);
00194 
00195     g_free(guid);
00196     
00197     return TRUE;
00198 }
00199 
00200 static gboolean
00201 account_type_handler (xmlNodePtr node, gpointer act_pdata)
00202 {
00203     struct account_pdata *pdata = act_pdata;
00204     GNCAccountType type = ACCT_TYPE_INVALID;
00205     char *string;
00206 
00207     string = (char*) xmlNodeGetContent (node->xmlChildrenNode);
00208     xaccAccountStringToType(string, &type);
00209     xmlFree (string);
00210 
00211     xaccAccountSetType(pdata->account, type);
00212 
00213     return TRUE;
00214 }
00215 
00216 static gboolean
00217 account_commodity_handler (xmlNodePtr node, gpointer act_pdata)
00218 {
00219     struct account_pdata *pdata = act_pdata;
00220     gnc_commodity *ref;
00221 
00222 //    ref = dom_tree_to_commodity_ref_no_engine(node, pdata->book);
00223     ref = dom_tree_to_commodity_ref(node, pdata->book);
00224     xaccAccountSetCommodity(pdata->account, ref);
00225 
00226     return TRUE;
00227 }
00228 
00229 static gboolean
00230 account_commodity_scu_handler (xmlNodePtr node, gpointer act_pdata)
00231 {
00232     struct account_pdata *pdata = act_pdata;
00233     gint64 val;
00234 
00235     dom_tree_to_integer(node, &val);
00236     xaccAccountSetCommoditySCU(pdata->account, val);
00237 
00238     return TRUE;
00239 }
00240 
00241 static gboolean
00242 account_non_standard_scu_handler (xmlNodePtr node, gpointer act_pdata)
00243 {
00244     struct account_pdata *pdata = act_pdata;
00245 
00246     xaccAccountSetNonStdSCU(pdata->account, TRUE);
00247 
00248     return TRUE;
00249 }
00250 
00251 /* ============================================================== */
00252 /* The following deprecated routines are here only to service 
00253  * older XML files. */
00254 
00255 static gboolean
00256 deprecated_account_currency_handler (xmlNodePtr node, gpointer act_pdata)
00257 {
00258     struct account_pdata *pdata = act_pdata;
00259     gnc_commodity *ref;
00260 
00261     PWARN("Obsolete xml tag will not be preserved."); 
00262     ref = dom_tree_to_commodity_ref_no_engine(node, pdata->book);
00263     DxaccAccountSetCurrency(pdata->account, ref);
00264 
00265     return TRUE;
00266 }
00267 
00268 static gboolean
00269 deprecated_account_currency_scu_handler (xmlNodePtr node, gpointer act_pdata)
00270 {
00271     PWARN("Obsolete xml tag will not be preserved."); 
00272     return TRUE;
00273 }
00274 
00275 static gboolean
00276 deprecated_account_security_handler (xmlNodePtr node, gpointer act_pdata)
00277 {
00278     struct account_pdata *pdata = act_pdata;
00279     gnc_commodity *ref;
00280 
00281     PWARN("Obsolete xml tag will not be preserved."); 
00282     if (!xaccAccountGetCommodity(pdata->account)) {
00283         ref = dom_tree_to_commodity_ref_no_engine(node, pdata->book);
00284         xaccAccountSetCommodity(pdata->account, ref);
00285     }
00286 
00287     return TRUE;
00288 }
00289 
00290 static gboolean
00291 deprecated_account_security_scu_handler (xmlNodePtr node, gpointer act_pdata)
00292 {
00293     struct account_pdata *pdata = act_pdata;
00294     gint64 val;
00295 
00296     PWARN("Obsolete xml tag will not be preserved."); 
00297     if (!xaccAccountGetCommoditySCU(pdata->account)) {
00298         dom_tree_to_integer(node, &val);
00299         xaccAccountSetCommoditySCU(pdata->account, val);
00300     }
00301 
00302     return TRUE;
00303 }
00304 
00305 /* ============================================================== */
00306 
00307 static gboolean
00308 account_slots_handler (xmlNodePtr node, gpointer act_pdata)
00309 {
00310     struct account_pdata *pdata = act_pdata;
00311 
00312     return dom_tree_to_kvp_frame_given
00313         (node, xaccAccountGetSlots (pdata->account));
00314 }
00315 
00316 static gboolean
00317 account_parent_handler (xmlNodePtr node, gpointer act_pdata)
00318 {
00319     struct account_pdata *pdata = act_pdata;
00320     Account *parent;
00321     GUID *gid;
00322 
00323     gid = dom_tree_to_guid(node);
00324     g_return_val_if_fail(gid, FALSE);
00325 
00326     parent = xaccAccountLookup(gid, pdata->book);
00327     if (!parent)
00328     {
00329       g_free (gid);
00330       g_return_val_if_fail(parent, FALSE);
00331     }
00332 
00333     gnc_account_append_child(parent, pdata->account);
00334 
00335     g_free (gid);
00336 
00337     return TRUE;
00338 }
00339 
00340 static gboolean
00341 account_code_handler(xmlNodePtr node, gpointer act_pdata)
00342 {
00343     struct account_pdata *pdata = act_pdata;
00344 
00345     return set_string(node, pdata->account, xaccAccountSetCode);
00346 }
00347 
00348 static gboolean
00349 account_description_handler(xmlNodePtr node, gpointer act_pdata)
00350 {
00351     struct account_pdata *pdata = act_pdata;
00352 
00353     return set_string(node, pdata->account, xaccAccountSetDescription);
00354 }
00355 
00356 static gboolean
00357 account_lots_handler(xmlNodePtr node, gpointer act_pdata)
00358 {
00359     struct account_pdata *pdata = act_pdata;
00360     xmlNodePtr mark;
00361 
00362     g_return_val_if_fail(node, FALSE);
00363     g_return_val_if_fail(node->xmlChildrenNode, FALSE);
00364 
00365     for(mark = node->xmlChildrenNode; mark; mark = mark->next)
00366     {
00367         GNCLot *lot;
00368         
00369         if(safe_strcmp("text", (char*) mark->name) == 0)
00370           continue;
00371 
00372         lot = dom_tree_to_lot(mark, pdata->book);
00373 
00374         if(lot)
00375         {
00376             xaccAccountInsertLot (pdata->account, lot);
00377         }
00378         else
00379         {
00380             return FALSE;
00381         }
00382     }
00383     return TRUE;
00384 }
00385 
00386 static struct dom_tree_handler account_handlers_v2[] = {
00387     { act_name_string, account_name_handler, 1, 0 },
00388     { act_id_string, account_id_handler, 1, 0 },
00389     { act_type_string, account_type_handler, 1, 0 },
00390     { act_commodity_string, account_commodity_handler, 0, 0 },
00391     { act_commodity_scu_string, account_commodity_scu_handler, 0, 0 },
00392     { act_non_standard_scu_string, account_non_standard_scu_handler, 0, 0 },
00393     { act_code_string, account_code_handler, 0, 0 },
00394     { act_description_string, account_description_handler, 0, 0},
00395     { act_slots_string, account_slots_handler, 0, 0 },
00396     { act_parent_string, account_parent_handler, 0, 0 },
00397     { act_lots_string, account_lots_handler, 0, 0 },
00398     
00399     /* These should not appear in  newer xml files; only in old
00400      * (circa gnucash-1.6) xml files. We maintain them for backward 
00401      * compatibility. */
00402     { act_currency_string, deprecated_account_currency_handler, 0, 0 },
00403     { act_currency_scu_string, deprecated_account_currency_scu_handler, 0, 0 },
00404     { act_security_string, deprecated_account_security_handler, 0, 0 },
00405     { act_security_scu_string, deprecated_account_security_scu_handler, 0, 0 },
00406     { NULL, 0, 0, 0 }
00407 };
00408 
00409 static gboolean
00410 gnc_account_end_handler(gpointer data_for_children,
00411                         GSList* data_from_children, GSList* sibling_data,
00412                         gpointer parent_data, gpointer global_data,
00413                         gpointer *result, const gchar *tag)
00414 {
00415     int successful;
00416     Account *acc, *parent, *root;
00417     xmlNodePtr tree = (xmlNodePtr)data_for_children;
00418     gxpf_data *gdata = (gxpf_data*)global_data;
00419     QofBook *book = gdata->bookdata;
00420     int type;
00421 
00422     successful = TRUE;
00423 
00424     if(parent_data)
00425     {
00426         return TRUE;
00427     }
00428 
00429     /* OK.  For some messed up reason this is getting called again with a
00430        NULL tag.  So we ignore those cases */
00431     if(!tag)
00432     {
00433         return TRUE;
00434     }
00435 
00436     g_return_val_if_fail(tree, FALSE);
00437 
00438     acc = dom_tree_to_account(tree, book);
00439     if(acc != NULL)
00440     {
00441         gdata->cb(tag, gdata->parsedata, acc);
00442         /*
00443          * Now return the account to the "edit" state.  At the end of reading
00444          * all the transactions, we will Commit.  This replaces #splits
00445          * rebalances with #accounts rebalances at the end.  A BIG win!
00446          */
00447         xaccAccountBeginEdit(acc);
00448 
00449         /* Backwards compatability.  If there's no parent, see if this
00450          * account is of type ROOT.  If not, find or create a ROOT
00451          * account and make that the parent. */
00452         parent = gnc_account_get_parent(acc);
00453         if (parent == NULL) {
00454             type = xaccAccountGetType(acc);
00455             if (type != ACCT_TYPE_ROOT) {
00456                 root = gnc_book_get_root_account(book);
00457                 if (root == NULL) {
00458                   root = gnc_account_create_root(book);
00459                 }
00460                 gnc_account_append_child(root, acc);
00461             }
00462         }
00463     }
00464 
00465     xmlFreeNode(tree);
00466 
00467     return acc != NULL;
00468 }
00469 
00470 Account*
00471 dom_tree_to_account (xmlNodePtr node, QofBook *book)
00472 {
00473     struct account_pdata act_pdata;
00474     Account *accToRet;
00475     gboolean successful;
00476 
00477     accToRet = xaccMallocAccount(book);
00478     xaccAccountBeginEdit(accToRet);
00479 
00480     act_pdata.account = accToRet;
00481     act_pdata.book = book;
00482 
00483     successful = dom_tree_generic_parse (node, account_handlers_v2,
00484                                          &act_pdata);
00485     if (successful) {
00486       xaccAccountCommitEdit (accToRet);
00487     } else {
00488         PERR ("failed to parse account tree");
00489         xaccAccountDestroy (accToRet);
00490         accToRet = NULL;
00491     }
00492 
00493     return accToRet;
00494 }
00495 
00496 sixtp*
00497 gnc_account_sixtp_parser_create(void)
00498 {
00499     return sixtp_dom_parser_new(gnc_account_end_handler, NULL, NULL);
00500 }
00501 
00502 /* ======================  END OF FILE ===================*/

Generated on Mon Sep 8 05:03:56 2008 for GnuCash by  doxygen 1.5.2