qofquery-serialize.c

00001 /********************************************************************\
00002  * qofquery-serialize.c -- Convert QofQuery to XML                  *
00003  * Copyright (C) 2001,2002,2004 Linas Vepstas <linas@linas.org>     *
00004  *                                                                  *
00005  * This program is free software; you can redistribute it and/or    *
00006  * modify it under the terms of the GNU General Public License as   *
00007  * published by the Free Software Foundation; either version 2 of   *
00008  * the License, or (at your option) any later version.              *
00009  *                                                                  *
00010  * This program is distributed in the hope that it will be useful,  *
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00013  * GNU General Public License for more details.                     *
00014  *                                                                  *
00015  * You should have received a copy of the GNU General Public License*
00016  * along with this program; if not, contact:                        *
00017  *                                                                  *
00018  * Free Software Foundation           Voice:  +1-617-542-5942       *
00019  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
00020  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
00021  *                                                                  *
00022 \********************************************************************/
00023 
00024 #include "config.h"
00025 
00026 #include "qofquery-serialize.h"
00027 #include "qofquery-p.h"
00028 #include "qofquerycore-p.h"
00029 #include "kvp_frame.h"
00030 
00031 /* NOTE: Development of this idea has ceased and this file is
00032 no longer included in the QOF library. It remains in CVS for now.*/
00033 
00034 /* ======================================================= */
00035 
00036 #define PUT_STR(TOK,VAL) {                           \
00037    xmlNodePtr node;                                  \
00038    const char * str = (VAL);                         \
00039    if (str && 0 != str[0])                           \
00040    {                                                 \
00041       node = xmlNewNode (NULL, TOK);                 \
00042       xmlNodeAddContent(node, str);                  \
00043       xmlAddChild (topnode, node);                   \
00044    }                                                 \
00045 }
00046 
00047 #define PUT_INT32(TOK,VAL) {                         \
00048    xmlNodePtr node;                                  \
00049    char buff[80];                                    \
00050    g_snprintf (buff, sizeof(buff), "%d", (VAL));     \
00051    node = xmlNewNode (NULL, TOK);                    \
00052    xmlNodeAddContent(node, buff);                    \
00053    xmlAddChild (topnode, node);                      \
00054 }
00055 
00056 #define PUT_INT64(TOK,VAL) {                         \
00057    xmlNodePtr node;                                  \
00058    char buff[80];                                    \
00059    g_snprintf (buff, sizeof(buff), "%" G_GINT64_FORMAT, (VAL));   \
00060    node = xmlNewNode (NULL, TOK);                    \
00061    xmlNodeAddContent(node, buff);                    \
00062    xmlAddChild (topnode, node);                      \
00063 }
00064 
00065 #define PUT_DBL(TOK,VAL) {                           \
00066    xmlNodePtr node;                                  \
00067    char buff[80];                                    \
00068    g_snprintf (buff, sizeof(buff), "%.18g", (VAL));  \
00069    node = xmlNewNode (NULL, TOK);                    \
00070    xmlNodeAddContent(node, buff);                    \
00071    xmlAddChild (topnode, node);                      \
00072 }
00073 
00074 #define PUT_GUID(TOK,VAL) {                          \
00075    xmlNodePtr node;                                  \
00076    char buff[80];                                    \
00077    guid_to_string_buff ((VAL), buff);                \
00078    node = xmlNewNode (NULL, TOK);                    \
00079    xmlNodeAddContent(node, buff);                    \
00080    xmlAddChild (topnode, node);                      \
00081 }
00082 
00083 #define PUT_DATE(TOK,VAL) {                          \
00084    xmlNodePtr node;                                  \
00085    char buff[80];                                    \
00086    gnc_timespec_to_iso8601_buff ((VAL), buff);       \
00087    node = xmlNewNode (NULL, TOK);                    \
00088    xmlNodeAddContent(node, buff);                    \
00089    xmlAddChild (topnode, node);                      \
00090 }
00091 
00092 #define PUT_NUMERIC(TOK,VAL) {                       \
00093    xmlNodePtr node;                                  \
00094    char *str;                                        \
00095    str = gnc_numeric_to_string (VAL);                \
00096    node = xmlNewNode (NULL, TOK);                    \
00097    xmlNodeAddContent(node, str);                     \
00098    g_free (str);                                     \
00099    xmlAddChild (topnode, node);                      \
00100 }
00101 
00102 #define PUT_BOOL(TOK,VAL) {                          \
00103    xmlNodePtr node;                                  \
00104    gboolean boll = (VAL);                            \
00105    node = xmlNewNode (NULL, TOK);                    \
00106    if (boll) {                                       \
00107       xmlNodeAddContent(node, "T");                  \
00108    } else {                                          \
00109       xmlNodeAddContent(node, "F");                  \
00110    }                                                 \
00111    xmlAddChild (topnode, node);                      \
00112 }
00113 
00114 #define PUT_HOW(TOK,VAL,A,B,C,D,E,F) {               \
00115    xmlNodePtr node;                                  \
00116    const char * str = "EQUAL";                       \
00117    switch (VAL)                                      \
00118    {                                                 \
00119       case QOF_COMPARE_##A: str = #A; break;         \
00120       case QOF_COMPARE_##B: str = #B; break;         \
00121       case QOF_COMPARE_##C: str = #C; break;         \
00122       case QOF_COMPARE_##D: str = #D; break;         \
00123       case QOF_COMPARE_##E: str = #E; break;         \
00124       case QOF_COMPARE_##F: str = #F; break;         \
00125    }                                                 \
00126    node = xmlNewNode (NULL, TOK);                    \
00127    xmlNodeAddContent(node, str);                     \
00128    xmlAddChild (topnode, node);                      \
00129 }
00130 
00131 #define PUT_MATCH2(TOK,VAL,PFX,A,B) {                \
00132    xmlNodePtr node;                                  \
00133    const char * str = #A;                            \
00134    switch (VAL)                                      \
00135    {                                                 \
00136       case QOF_##PFX##_##A: str = #A; break;         \
00137       case QOF_##PFX##_##B: str = #B; break;         \
00138    }                                                 \
00139    node = xmlNewNode (NULL, TOK);                    \
00140    xmlNodeAddContent(node, str);                     \
00141    xmlAddChild (topnode, node);                      \
00142 }
00143 
00144 #define PUT_MATCH3(TOK,VAL,PFX,A,B,C) {              \
00145    xmlNodePtr node;                                  \
00146    const char * str = #A;                            \
00147    switch (VAL)                                      \
00148    {                                                 \
00149       case QOF_##PFX##_##A: str = #A; break;         \
00150       case QOF_##PFX##_##B: str = #B; break;         \
00151       case QOF_##PFX##_##C: str = #C; break;         \
00152    }                                                 \
00153    node = xmlNewNode (NULL, TOK);                    \
00154    xmlNodeAddContent(node, str);                     \
00155    xmlAddChild (topnode, node);                      \
00156 }
00157 
00158 #define PUT_MATCH5(TOK,VAL,PFX,A,B,C,D,E) {          \
00159    xmlNodePtr node;                                  \
00160    const char * str = #A;                            \
00161    switch (VAL)                                      \
00162    {                                                 \
00163       case QOF_##PFX##_##A: str = #A; break;         \
00164       case QOF_##PFX##_##B: str = #B; break;         \
00165       case QOF_##PFX##_##C: str = #C; break;         \
00166       case QOF_##PFX##_##D: str = #D; break;         \
00167       case QOF_##PFX##_##E: str = #E; break;         \
00168    }                                                 \
00169    node = xmlNewNode (NULL, TOK);                    \
00170    xmlNodeAddContent(node, str);                     \
00171    xmlAddChild (topnode, node);                      \
00172 }
00173 
00174 /* ======================================================= */
00175 
00176 static void
00177 qof_kvp_value_to_xml (KvpValue * kval, xmlNodePtr topnode)
00178 {
00179     KvpValueType kvt = kvp_value_get_type (kval);
00180 
00181     switch (kvt)
00182     {
00183     case KVP_TYPE_GINT64:
00184         PUT_INT64 ("qofquery:int64", kvp_value_get_gint64 (kval));
00185         break;
00186     case KVP_TYPE_DOUBLE:
00187         PUT_DBL ("qofquery:double", kvp_value_get_double (kval));
00188         break;
00189     case KVP_TYPE_NUMERIC:
00190         PUT_NUMERIC ("qofquery:numeric", kvp_value_get_numeric (kval));
00191         break;
00192     case KVP_TYPE_GUID:
00193         PUT_GUID ("qofquery:guid", kvp_value_get_guid (kval));
00194         break;
00195     case KVP_TYPE_STRING:
00196         PUT_STR ("qofquery:string", kvp_value_get_string (kval));
00197         break;
00198     case KVP_TYPE_TIMESPEC:
00199         PUT_DATE ("qofquery:date", kvp_value_get_timespec (kval));
00200         break;
00201     case KVP_TYPE_BINARY:
00202     case KVP_TYPE_GLIST:
00203     case KVP_TYPE_FRAME:
00204         // XXX don't know how to support these.
00205         break;
00206     }
00207 }
00208 
00209 /* ======================================================= */
00210 
00211 static xmlNodePtr
00212 qof_query_pred_data_to_xml (QofQueryPredData * pd)
00213 {
00214     GList *n;
00215     GSList *ns;
00216     xmlNodePtr topnode;
00217     query_guid_t pdata_g;
00218     query_string_t pdata_s;
00219     query_numeric_t pdata_n;
00220     query_kvp_t pdata_k;
00221     query_date_t pdata_d;
00222     query_int64_t pdata_i64;
00223     query_int32_t pdata_i32;
00224     query_double_t pdata_db;
00225     query_boolean_t pdata_bool;
00226     query_char_t pdata_c;
00227 
00228     if (!safe_strcmp (pd->type_name, QOF_TYPE_GUID))
00229     {
00230         topnode = xmlNewNode (NULL, "qofquery:pred-guid");
00231         /* GUID Predicate doesn't do a PUT_HOW */
00232 
00233         pdata_g = (query_guid_t) pd;
00234         PUT_MATCH5 ("qofquery:guid-match", pdata_g->options,
00235             GUID_MATCH, ANY, ALL, NONE, NULL, LIST_ANY);
00236 
00237         for (n = pdata_g->guids; n; n = n->next)
00238         {
00239             PUT_GUID ("qofquery:guid", n->data);
00240         }
00241         return topnode;
00242     }
00243     if (!safe_strcmp (pd->type_name, QOF_TYPE_STRING))
00244     {
00245         topnode = xmlNewNode (NULL, "qofquery:pred-string");
00246         PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE,
00247             NEQ);
00248 
00249         pdata_s = (query_string_t) pd;
00250         PUT_MATCH2 ("qofquery:string-match", pdata_s->options,
00251             STRING_MATCH, NORMAL, CASEINSENSITIVE);
00252         PUT_BOOL ("qofquery:is-regex", pdata_s->is_regex);
00253         PUT_STR ("qofquery:string", pdata_s->matchstring);
00254         return topnode;
00255     }
00256     if (!safe_strcmp (pd->type_name, QOF_TYPE_NUMERIC))
00257     {
00258         topnode = xmlNewNode (NULL, "qofquery:pred-numeric");
00259         PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE,
00260             NEQ);
00261 
00262         pdata_n = (query_numeric_t) pd;
00263         PUT_MATCH3 ("qofquery:numeric-match", pdata_n->options,
00264             NUMERIC_MATCH, DEBIT, CREDIT, ANY);
00265 
00266         PUT_NUMERIC ("qofquery:numeric", pdata_n->amount);
00267         return topnode;
00268     }
00269     if (!safe_strcmp (pd->type_name, QOF_TYPE_KVP))
00270     {
00271         topnode = xmlNewNode (NULL, "qofquery:pred-kvp");
00272         PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE,
00273             NEQ);
00274 
00275         pdata_k = (query_kvp_t) pd;
00276         for (ns = pdata_k->path; ns; ns = ns->next)
00277         {
00278             PUT_STR ("qofquery:kvp-path", ns->data);
00279         }
00280         qof_kvp_value_to_xml (pdata_k->value, topnode);
00281         return topnode;
00282     }
00283     if (!safe_strcmp (pd->type_name, QOF_TYPE_DATE))
00284     {
00285         topnode = xmlNewNode (NULL, "qofquery:pred-date");
00286         PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE,
00287             NEQ);
00288 
00289         pdata_d = (query_date_t) pd;
00290 
00291         PUT_MATCH2 ("qofquery:date-match", pdata_d->options,
00292             DATE_MATCH, NORMAL, DAY);
00293 
00294         PUT_DATE ("qofquery:date", pdata_d->date);
00295         return topnode;
00296     }
00297     if (!safe_strcmp (pd->type_name, QOF_TYPE_INT64))
00298     {
00299         topnode = xmlNewNode (NULL, "qofquery:pred-int64");
00300         PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE,
00301             NEQ);
00302 
00303         pdata_i64 = (query_int64_t) pd;
00304         PUT_INT64 ("qofquery:int64", pdata_i64->val);
00305         return topnode;
00306     }
00307     if (!safe_strcmp (pd->type_name, QOF_TYPE_INT32))
00308     {
00309         topnode = xmlNewNode (NULL, "qofquery:pred-int32");
00310         PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE,
00311             NEQ);
00312 
00313         pdata_i32 = (query_int32_t) pd;
00314 
00315         PUT_INT32 ("qofquery:int32", pdata_i32->val);
00316         return topnode;
00317     }
00318     if (!safe_strcmp (pd->type_name, QOF_TYPE_DOUBLE))
00319     {
00320         topnode = xmlNewNode (NULL, "qofquery:pred-double");
00321         PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE,
00322             NEQ);
00323 
00324         pdata_db = (query_double_t) pd;
00325 
00326         PUT_DBL ("qofquery:double", pdata_db->val);
00327         return topnode;
00328     }
00329     if (!safe_strcmp (pd->type_name, QOF_TYPE_BOOLEAN))
00330     {
00331         topnode = xmlNewNode (NULL, "qofquery:pred-boolean");
00332         PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE,
00333             NEQ);
00334 
00335         pdata_bool = (query_boolean_t) pd;
00336 
00337         PUT_BOOL ("qofquery:boolean", pdata_bool->val);
00338         return topnode;
00339     }
00340     if (!safe_strcmp (pd->type_name, QOF_TYPE_CHAR))
00341     {
00342         topnode = xmlNewNode (NULL, "qofquery:pred-char");
00343         /* There is no PUT_HOW for char-match */
00344         pdata_c = (query_char_t) pd;
00345 
00346         PUT_MATCH2 ("qofquery:char-match", pdata_c->options,
00347             CHAR_MATCH, ANY, NONE);
00348 
00349         PUT_STR ("qofquery:char-list", pdata_c->char_list);
00350         return topnode;
00351     }
00352     return NULL;
00353 }
00354 
00355 /* ======================================================= */
00356 
00357 static xmlNodePtr
00358 qof_query_param_path_to_xml (GSList * param_path)
00359 {
00360     xmlNodePtr topnode;
00361     GSList *n;
00362     QofIdTypeConst path;
00363 
00364     n = param_path;
00365     topnode = xmlNewNode (NULL, "qofquery:param-path");
00366     for (; n; n = n->next)
00367     {
00368         path = n->data;
00369         if (!path)
00370             continue;
00371         PUT_STR ("qofquery:param", path);
00372     }
00373     return topnode;
00374 }
00375 
00376 /* ======================================================= */
00377 
00378 static xmlNodePtr
00379 qof_query_one_term_to_xml (QofQueryTerm * qt)
00380 {
00381     xmlNodePtr node;
00382     xmlNodePtr term;
00383     xmlNodePtr topnode;
00384     gboolean invert;
00385     GSList *path;
00386     QofQueryPredData *pd;
00387 
00388     invert = qof_query_term_is_inverted (qt);
00389     term = xmlNewNode (NULL, "qofquery:term");
00390     topnode = term;
00391     path = qof_query_term_get_param_path (qt);
00392     pd = qof_query_term_get_pred_data (qt);
00393     if (invert)
00394     {
00395         /* inverter becomes new top mode */
00396         topnode = xmlNewNode (NULL, "qofquery:invert");
00397         xmlAddChild (term, topnode);
00398     }
00399 
00400     node = qof_query_param_path_to_xml (path);
00401     if (node)
00402         xmlAddChild (topnode, node);
00403 
00404     node = qof_query_pred_data_to_xml (pd);
00405     if (node)
00406         xmlAddChild (topnode, node);
00407 
00408     return term;
00409 }
00410 
00411 /* ======================================================= */
00412 
00413 static xmlNodePtr
00414 qof_query_and_terms_to_xml (GList * and_terms)
00415 {
00416     xmlNodePtr terms;
00417     GList *n;
00418     QofQueryTerm *qt;
00419     xmlNodePtr t;
00420 
00421     terms = xmlNewNode (NULL, "qofquery:and-terms");
00422     n = and_terms;
00423     for (; n; n = n->next)
00424     {
00425         qt = n->data;
00426         if (!qt)
00427             continue;
00428 
00429         t = qof_query_one_term_to_xml (n->data);
00430         if (t)
00431             xmlAddChild (terms, t);
00432     }
00433     return terms;
00434 }
00435 
00436 /* ======================================================= */
00437 
00438 static xmlNodePtr
00439 qof_query_terms_to_xml (QofQuery * q)
00440 {
00441     xmlNodePtr terms;
00442     GList *n;
00443     xmlNodePtr andt;
00444 
00445     terms = NULL;
00446     n = qof_query_get_terms (q);
00447     if (!n)
00448         return NULL;
00449     terms = xmlNewNode (NULL, "qofquery:or-terms");
00450 
00451     for (; n; n = n->next)
00452     {
00453         andt = qof_query_and_terms_to_xml (n->data);
00454         if (andt)
00455             xmlAddChild (terms, andt);
00456     }
00457     return terms;
00458 }
00459 
00460 /* ======================================================= */
00461 
00462 static xmlNodePtr
00463 qof_query_sorts_to_xml (QofQuery * q)
00464 {
00465     QofQuerySort *s[3];
00466     xmlNodePtr sortlist;
00467     GSList *plist;
00468     xmlNodePtr sort;
00469     xmlNodePtr topnode;
00470     gboolean increasing;
00471     gint opt;
00472     xmlNodePtr pl;
00473     int i;
00474 
00475     qof_query_get_sorts (q, &s[0], &s[1], &s[2]);
00476 
00477     if (NULL == s[0])
00478         return NULL;
00479 
00480     sortlist = xmlNewNode (NULL, "qofquery:sort-list");
00481     for (i = 0; i < 3; i++)
00482     {
00483         if (NULL == s[i])
00484             continue;
00485 
00486         plist = qof_query_sort_get_param_path (s[i]);
00487         if (!plist)
00488             continue;
00489 
00490         sort = xmlNewNode (NULL, "qofquery:sort");
00491         xmlAddChild (sortlist, sort);
00492 
00493         topnode = sort;
00494 
00495         increasing = qof_query_sort_get_increasing (s[i]);
00496         PUT_STR ("qofquery:order",
00497             increasing ? "DESCENDING" : "ASCENDING");
00498 
00499         opt = qof_query_sort_get_sort_options (s[i]);
00500         PUT_INT32 ("qofquery:options", opt);
00501 
00502         pl = qof_query_param_path_to_xml (plist);
00503         if (pl)
00504             xmlAddChild (sort, pl);
00505     }
00506 
00507     return sortlist;
00508 }
00509 
00510 /* ======================================================= */
00511 
00512 static void
00513 do_qof_query_to_xml (QofQuery * q, xmlNodePtr topnode)
00514 {
00515     QofIdType search_for;
00516     xmlNodePtr terms;
00517     xmlNodePtr sorts;
00518     gint max_results;
00519 
00520     search_for = qof_query_get_search_for (q);
00521     PUT_STR ("qofquery:search-for", search_for);
00522 
00523     terms = qof_query_terms_to_xml (q);
00524     if (terms)
00525         xmlAddChild (topnode, terms);
00526 
00527     sorts = qof_query_sorts_to_xml (q);
00528     if (sorts)
00529         xmlAddChild (topnode, sorts);
00530 
00531     max_results = qof_query_get_max_results (q);
00532     PUT_INT32 ("qofquery:max-results", max_results);
00533 }
00534 
00535 /* ======================================================= */
00536 
00537 xmlNodePtr
00538 qof_query_to_xml (QofQuery * q)
00539 {
00540     xmlNodePtr topnode;
00541     xmlNodePtr node;
00542     xmlNsPtr ns;
00543 
00544     topnode = xmlNewNode (NULL, "qof:qofquery");
00545     xmlSetProp (topnode, "version", "1.0.1");
00546 
00547     // XXX path to DTD is wrong
00548     // ns = xmlNewNs (topnode, "file:" "/usr/share/lib" "/qofquery.dtd", "qof");
00549 
00550     do_qof_query_to_xml (q, topnode);
00551 
00552     return topnode;
00553 }
00554 
00555 /* =============================================================== */
00556 
00557 #ifdef UNIT_TEST
00558 
00559 #include <stdio.h>
00560 #include <qof/qofsql.h>
00561 
00562 int
00563 main (int argc, char *argv[])
00564 {
00565     QofQuery *q;
00566     QofSqlQuery *sq;
00567     xmlDocPtr doc;
00568     xmlNodePtr topnode;
00569     xmlChar *xbuf;
00570     int bufsz;
00571     xmlOutputBufferPtr xbuf;
00572 
00573     qof_query_init ();
00574     qof_object_initialize ();
00575 
00576     static QofParam params[] = {
00577         {"adate", QOF_TYPE_DATE, NULL, NULL},
00578         {"aint", QOF_TYPE_INT32, NULL, NULL},
00579         {"aint64", QOF_TYPE_INT64, NULL, NULL},
00580         {"astr", QOF_TYPE_STRING, NULL, NULL},
00581         {NULL},
00582     };
00583 
00584     qof_class_register ("GncABC", NULL, params);
00585     sq = qof_sql_query_new ();
00586 
00587     qof_sql_query_parse (sq,
00588         "SELECT * from GncABC WHERE aint = 123 "
00589         "or not astr=\'asdf\' " "and aint64 = 9876123456789;");
00590     // qof_sql_query_parse (sq, "SELECT * from GncABC;");
00591     q = qof_sql_query_get_query (sq);
00592 
00593     qof_query_print (q);
00594 
00595     doc = doc = xmlNewDoc ("1.0");
00596     topnode = qof_query_to_xml (q);
00597     xmlDocSetRootElement (doc, topnode);
00598 
00599     xmlDocDumpFormatMemory (doc, &xbuf, &bufsz, 1);
00600 
00601     printf ("%s\n", xbuf);
00602     xmlFree (xbuf);
00603     xmlFreeDoc (doc);
00604 
00605 #if 0
00606     printf ("duude\n");
00607     // xmlOutputBufferPtr xbuf = xmlAllocOutputBuffer (enc);
00608     xbuf = xmlOutputBufferCreateFile (stdout, NULL);
00609     printf ("duude\n");
00610 
00611     xbuf = xmlOutputBufferCreateFd (1, NULL);
00612     printf ("duude\n");
00613     xmlNodeDumpOutput (xbuf, NULL, topnode, 99, 99, "iso-8859-1");
00614     // xmlElemDump (stdout, NULL, topnode);
00615 #endif
00616 
00617     return 0;
00618 }
00619 
00620 #endif /* UNIT_TEST */
00621 
00622 /* ======================== END OF FILE =================== */

Generated on Thu Jan 31 22:50:26 2008 for QOF by  doxygen 1.5.4