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  * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652       *
00020  * Boston, MA  02111-1307,  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, NEQ);
00247 
00248                 pdata_s = (query_string_t) pd;
00249                 PUT_MATCH2("qofquery:string-match", pdata_s->options,
00250                        STRING_MATCH, NORMAL, CASEINSENSITIVE);
00251                 PUT_BOOL ("qofquery:is-regex", pdata_s->is_regex);
00252                 PUT_STR ("qofquery:string", pdata_s->matchstring);
00253                 return topnode;
00254         }
00255         if (!safe_strcmp (pd->type_name, QOF_TYPE_NUMERIC))
00256         {
00257                 topnode = xmlNewNode (NULL, "qofquery:pred-numeric");
00258                 PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
00259 
00260                 pdata_n = (query_numeric_t) pd;
00261                 PUT_MATCH3("qofquery:numeric-match", pdata_n->options,
00262                                  NUMERIC_MATCH, DEBIT, CREDIT, ANY);
00263                 
00264                 PUT_NUMERIC ("qofquery:numeric", pdata_n->amount);
00265                 return topnode;
00266         }
00267         if (!safe_strcmp (pd->type_name, QOF_TYPE_KVP))
00268         {
00269                 topnode = xmlNewNode (NULL, "qofquery:pred-kvp");
00270                 PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
00271 
00272                 pdata_k = (query_kvp_t) pd;
00273                 for (ns=pdata_k->path; ns; ns=ns->next)
00274                 {
00275                         PUT_STR ("qofquery:kvp-path", ns->data);
00276                 }
00277                 qof_kvp_value_to_xml (pdata_k->value, topnode);
00278                 return topnode;
00279         }
00280         if (!safe_strcmp (pd->type_name, QOF_TYPE_DATE))
00281         {
00282                 topnode = xmlNewNode (NULL, "qofquery:pred-date");
00283                 PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
00284 
00285                 pdata_d = (query_date_t) pd;
00286                 
00287                 PUT_MATCH2("qofquery:date-match", pdata_d->options,
00288                                  DATE_MATCH, NORMAL, DAY);
00289 
00290                 PUT_DATE ("qofquery:date", pdata_d->date);
00291                 return topnode;
00292         }
00293         if (!safe_strcmp (pd->type_name, QOF_TYPE_INT64))
00294         {
00295                 topnode = xmlNewNode (NULL, "qofquery:pred-int64");
00296                 PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
00297 
00298                 pdata_i64 = (query_int64_t) pd;
00299                 PUT_INT64 ("qofquery:int64", pdata_i64->val);
00300                 return topnode;
00301         }
00302         if (!safe_strcmp (pd->type_name, QOF_TYPE_INT32))
00303         {
00304                 topnode = xmlNewNode (NULL, "qofquery:pred-int32");
00305                 PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
00306 
00307                 pdata_i32 = (query_int32_t) pd;
00308                 
00309                 PUT_INT32 ("qofquery:int32", pdata_i32->val);
00310                 return topnode;
00311         }
00312         if (!safe_strcmp (pd->type_name, QOF_TYPE_DOUBLE))
00313         {
00314                 topnode = xmlNewNode (NULL, "qofquery:pred-double");
00315                 PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
00316 
00317                 pdata_db = (query_double_t) pd;
00318                 
00319                 PUT_DBL ("qofquery:double", pdata_db->val);
00320                 return topnode;
00321         }
00322         if (!safe_strcmp (pd->type_name, QOF_TYPE_BOOLEAN))
00323         {
00324                 topnode = xmlNewNode (NULL, "qofquery:pred-boolean");
00325                 PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
00326 
00327                 pdata_bool = (query_boolean_t) pd;
00328                 
00329                 PUT_BOOL ("qofquery:boolean", pdata_bool->val);
00330                 return topnode;
00331         }
00332         if (!safe_strcmp (pd->type_name, QOF_TYPE_CHAR))
00333         {
00334                 topnode = xmlNewNode (NULL, "qofquery:pred-char");
00335                 /* There is no PUT_HOW for char-match */
00336                 pdata_c = (query_char_t) pd;
00337                 
00338                 PUT_MATCH2("qofquery:char-match", pdata_c->options,
00339                                  CHAR_MATCH, ANY, NONE);
00340                 
00341                 PUT_STR ("qofquery:char-list", pdata_c->char_list);
00342                 return topnode;
00343         }
00344         return NULL;
00345 }
00346 
00347 /* ======================================================= */
00348 
00349 static xmlNodePtr
00350 qof_query_param_path_to_xml (GSList *param_path)
00351 {
00352         xmlNodePtr topnode;
00353         GSList *n;
00354         QofIdTypeConst path;
00355         
00356         n = param_path;
00357         topnode = xmlNewNode (NULL, "qofquery:param-path");
00358         for ( ; n; n=n->next)
00359         {
00360                 path = n->data;
00361                 if (!path) continue;
00362                 PUT_STR ("qofquery:param", path);
00363         }
00364         return topnode;
00365 }
00366 
00367 /* ======================================================= */
00368 
00369 static xmlNodePtr
00370 qof_query_one_term_to_xml (QofQueryTerm *qt)
00371 {
00372         xmlNodePtr node;
00373         xmlNodePtr term;
00374         xmlNodePtr topnode;
00375         gboolean invert;
00376         GSList *path;
00377         QofQueryPredData *pd;
00378 
00379         invert = qof_query_term_is_inverted (qt);
00380         term = xmlNewNode (NULL, "qofquery:term");
00381         topnode = term;
00382         path = qof_query_term_get_param_path (qt);
00383         pd = qof_query_term_get_pred_data (qt);
00384         if (invert)
00385         {
00386                 /* inverter becomes new top mode */
00387                 topnode = xmlNewNode (NULL, "qofquery:invert");
00388                 xmlAddChild (term, topnode);
00389         }
00390 
00391         node = qof_query_param_path_to_xml (path);
00392         if (node) xmlAddChild (topnode, node);
00393 
00394         node = qof_query_pred_data_to_xml (pd);
00395         if (node) xmlAddChild (topnode, node);
00396 
00397         return term;
00398 }
00399 
00400 /* ======================================================= */
00401 
00402 static xmlNodePtr
00403 qof_query_and_terms_to_xml (GList *and_terms)
00404 {
00405         xmlNodePtr terms;
00406         GList *n;
00407         QofQueryTerm *qt;
00408         xmlNodePtr t;
00409         
00410         terms = xmlNewNode (NULL, "qofquery:and-terms");
00411         n = and_terms;
00412         for ( ; n; n=n->next)
00413         {
00414                 qt = n->data;
00415                 if (!qt) continue;
00416 
00417                 t = qof_query_one_term_to_xml (n->data);
00418                 if (t) xmlAddChild (terms, t);
00419         }
00420         return terms;
00421 }
00422 
00423 /* ======================================================= */
00424 
00425 static xmlNodePtr
00426 qof_query_terms_to_xml (QofQuery *q)
00427 {
00428         xmlNodePtr terms;
00429         GList *n;
00430         xmlNodePtr andt;
00431         
00432         terms = NULL;
00433         n = qof_query_get_terms (q);
00434         if (!n) return NULL;
00435         terms = xmlNewNode (NULL, "qofquery:or-terms");
00436 
00437         for ( ; n; n=n->next)
00438         {
00439                 andt = qof_query_and_terms_to_xml (n->data);
00440                 if (andt) xmlAddChild (terms, andt);
00441         }
00442         return terms;
00443 }
00444 
00445 /* ======================================================= */
00446 
00447 static xmlNodePtr
00448 qof_query_sorts_to_xml (QofQuery *q)
00449 {
00450         QofQuerySort *s[3];
00451         xmlNodePtr sortlist;
00452         GSList *plist;
00453         xmlNodePtr sort;
00454         xmlNodePtr topnode;
00455         gboolean increasing;
00456         gint opt;
00457         xmlNodePtr pl;
00458         int i;
00459         
00460         qof_query_get_sorts (q, &s[0], &s[1], &s[2]);
00461 
00462         if (NULL == s[0]) return NULL;
00463 
00464         sortlist = xmlNewNode (NULL, "qofquery:sort-list");
00465         for (i=0; i<3; i++)
00466         {
00467                 if (NULL == s[i]) continue;
00468 
00469                 plist = qof_query_sort_get_param_path (s[i]);
00470                 if (!plist) continue;
00471 
00472                 sort = xmlNewNode (NULL, "qofquery:sort");
00473                 xmlAddChild (sortlist, sort);
00474 
00475                 topnode = sort;
00476 
00477                 increasing = qof_query_sort_get_increasing (s[i]);
00478                 PUT_STR ("qofquery:order", increasing ? "DESCENDING" : "ASCENDING");
00479 
00480                 opt = qof_query_sort_get_sort_options (s[i]);
00481                 PUT_INT32 ("qofquery:options", opt);
00482 
00483                 pl = qof_query_param_path_to_xml (plist);
00484                 if (pl) xmlAddChild (sort, pl);
00485         }
00486 
00487         return sortlist;
00488 }
00489 
00490 /* ======================================================= */
00491 
00492 static void
00493 do_qof_query_to_xml (QofQuery *q, xmlNodePtr topnode)
00494 {
00495         QofIdType search_for;
00496         xmlNodePtr terms;
00497         xmlNodePtr sorts;
00498         gint max_results;
00499         
00500         search_for = qof_query_get_search_for (q);
00501         PUT_STR ("qofquery:search-for", search_for);
00502 
00503         terms = qof_query_terms_to_xml(q);
00504         if (terms) xmlAddChild (topnode, terms);
00505 
00506         sorts = qof_query_sorts_to_xml (q);
00507         if (sorts) xmlAddChild (topnode, sorts);
00508 
00509         max_results = qof_query_get_max_results (q);
00510         PUT_INT32 ("qofquery:max-results", max_results);
00511 }
00512 
00513 /* ======================================================= */
00514 
00515 xmlNodePtr
00516 qof_query_to_xml (QofQuery *q)
00517 {
00518         xmlNodePtr topnode;
00519         xmlNodePtr node;
00520         xmlNsPtr   ns;
00521 
00522         topnode = xmlNewNode(NULL, "qof:qofquery");
00523         xmlSetProp(topnode, "version", "1.0.1");
00524 
00525         // XXX path to DTD is wrong
00526         // ns = xmlNewNs (topnode, "file:" "/usr/share/lib" "/qofquery.dtd", "qof");
00527 
00528         do_qof_query_to_xml (q, topnode);
00529 
00530         return topnode;
00531 }
00532 
00533 /* =============================================================== */
00534 
00535 #ifdef UNIT_TEST
00536 
00537 #include <stdio.h>
00538 #include <qof/qofsql.h>
00539 
00540 int main (int argc, char * argv[])
00541 {
00542         QofQuery *q;
00543         QofSqlQuery *sq;
00544         xmlDocPtr doc;
00545         xmlNodePtr topnode;
00546         xmlChar *xbuf;
00547         int bufsz;
00548         xmlOutputBufferPtr xbuf;
00549         
00550         qof_query_init();
00551         qof_object_initialize ();
00552 
00553         static QofParam params[] = {
00554                 { "adate",  QOF_TYPE_DATE, NULL, NULL},
00555                 { "aint",   QOF_TYPE_INT32, NULL, NULL},
00556                 { "aint64", QOF_TYPE_INT64, NULL, NULL},
00557                 { "astr",   QOF_TYPE_STRING, NULL, NULL},
00558                 { NULL },
00559         };
00560 
00561         qof_class_register ("GncABC", NULL, params);
00562         sq = qof_sql_query_new();
00563 
00564         qof_sql_query_parse (sq, 
00565             "SELECT * from GncABC WHERE aint = 123 "
00566             "or not astr=\'asdf\' "
00567             "and aint64 = 9876123456789;");
00568         // qof_sql_query_parse (sq, "SELECT * from GncABC;");
00569         q = qof_sql_query_get_query (sq);
00570 
00571         qof_query_print (q);
00572 
00573         doc = doc = xmlNewDoc("1.0");
00574         topnode = qof_query_to_xml (q);
00575         xmlDocSetRootElement(doc,topnode);
00576 
00577         xmlDocDumpFormatMemory (doc, &xbuf, &bufsz, 1);
00578 
00579         printf ("%s\n", xbuf);
00580         xmlFree (xbuf);
00581         xmlFreeDoc(doc);
00582 
00583 #if 0
00584 printf ("duude\n");
00585         // xmlOutputBufferPtr xbuf = xmlAllocOutputBuffer (enc);
00586         xbuf = xmlOutputBufferCreateFile (stdout, NULL);
00587 printf ("duude\n");
00588 
00589         xbuf = xmlOutputBufferCreateFd (1, NULL);
00590 printf ("duude\n");
00591         xmlNodeDumpOutput (xbuf, NULL, topnode, 99, 99, "iso-8859-1");
00592         // xmlElemDump (stdout, NULL, topnode);
00593 #endif
00594 
00595         return 0;
00596 }
00597 
00598 #endif /* UNIT_TEST */
00599 
00600 /* ======================== END OF FILE =================== */

Generated on Fri Oct 21 15:49:55 2005 for QOF by  doxygen 1.4.5