Main Page | Class Hierarchy | Data Structures | File List | Data Fields | Globals

# ofx_sgml.cpp

Go to the documentation of this file.

    00001 /***************************************************************************
    00002                           ofx_sgml.cpp
    00003                           -------------------
    00004     copyright            : (C) 2002 by Benoit Grégoire
    00005     email                : bock@step.polymtl.ca
    00006 ***************************************************************************/
    00012 /***************************************************************************
    00013  *                                                                         *
    00014  *   This program is free software; you can redistribute it and/or modify  *
    00015  *   it under the terms of the GNU General Public License as published by  *
    00016  *   the Free Software Foundation; either version 2 of the License, or     *
    00017  *   (at your option) any later version.                                   *
    00018  *                                                                         *
    00019  ***************************************************************************/
    00020
    00021 #ifdef HAVE_CONFIG_H
    00022 #include <config.h>
    00023 #endif
    00024
    00025 #include <iostream>
    00026 #include <stdlib.h>
    00027 #include <string>
    00028 #include "ParserEventGeneratorKit.h"
    00029 #include "libofx.h"
    00030 #include "ofx_utilities.hh"
    00031 #include "messages.hh"
    00032 #include "ofx_containers.hh"
    00033 #include "ofx_sgml.hh"
    00034
    00035 using namespace std;
    00036
    00037 OfxMainContainer * MainContainer = NULL;
    00038 extern SGMLApplication::OpenEntityPtr entity_ptr;
    00039 extern SGMLApplication::Position position;
    00040
    00041
    00044 class OFXApplication : public SGMLApplication
    00045 {
    00046 private:
    00047   OfxGenericContainer *curr_container_element;
    00048   OfxGenericContainer *tmp_container_element;
    00049   bool is_data_element;
    00050   string incoming_data;
    00051   LibofxContext * libofx_context;
    00052
    00053 public:
    00054
    00055   OFXApplication (LibofxContext * p_libofx_context)
    00056   {
    00057     MainContainer=NULL;
    00058     curr_container_element = NULL;
    00059     is_data_element = false;
    00060     libofx_context=p_libofx_context;
    00061   }
    00062
    00067   void startElement (const StartElementEvent & event)
    00068   {
    00069     string identifier;
    00070     CharStringtostring (event.gi, identifier);
    00071     message_out(PARSER,"startElement event received from OpenSP for element " + identifier);
    00072
    00073     position = event.pos;
    00074
    00075     switch (event.contentType)
    00076       {
    00077       case StartElementEvent::empty:    message_out(ERROR,"StartElementEvent::empty\n");
    00078         break;
    00079       case StartElementEvent::cdata:    message_out(ERROR,"StartElementEvent::cdata\n");
    00080         break;
    00081       case StartElementEvent::rcdata:   message_out(ERROR,"StartElementEvent::rcdata\n");
    00082         break;
    00083       case StartElementEvent::mixed:    message_out(PARSER,"StartElementEvent::mixed");
    00084         is_data_element = true;
    00085         break;
    00086       case StartElementEvent::element:  message_out(PARSER,"StartElementEvent::element");
    00087         is_data_element = false;
    00088         break;
    00089       default:
    00090         message_out(ERROR,"Unknow SGML content type?!?!?!? OpenSP interface changed?");
    00091       }
    00092
    00093     if (is_data_element == false)
    00094       {
    00095         /*------- The following are OFX entities ---------------*/
    00096
    00097         if (identifier == "OFX")
    00098           {
    00099             message_out (PARSER, "Element " + identifier + " found");
    00100             MainContainer = new OfxMainContainer (libofx_context, curr_container_element, identifier);
    00101             curr_container_element = MainContainer;
    00102           }
    00103         else if (identifier == "STATUS")
    00104           {
    00105             message_out (PARSER, "Element " + identifier + " found");
    00106             curr_container_element = new OfxStatusContainer (libofx_context, curr_container_element, identifier);
    00107           }
    00108         else if (identifier == "STMTRS" ||
    00109                  identifier == "CCSTMTRS" ||
    00110                  identifier == "INVSTMTRS")
    00111           {
    00112             message_out (PARSER, "Element " + identifier + " found");
    00113             curr_container_element = new OfxStatementContainer (libofx_context, curr_container_element, identifier);
    00114           }
    00115         else if (identifier == "BANKTRANLIST")
    00116           {
    00117             message_out (PARSER, "Element " + identifier + " found");
    00118             //BANKTRANLIST ignored, we will process it's attributes directly inside the STATEMENT,
    00119             if(curr_container_element->type!="STATEMENT")
    00120               {
    00121                 message_out(ERROR,"Element " + identifier + " found while not inside a STATEMENT container");
    00122               }
    00123             else
    00124               {
    00125                 curr_container_element = new OfxPushUpContainer (libofx_context, curr_container_element, identifier);
    00126               }
    00127           }
    00128         else if (identifier == "STMTTRN")
    00129           {
    00130             message_out (PARSER, "Element " + identifier + " found");
    00131             curr_container_element = new OfxBankTransactionContainer (libofx_context, curr_container_element, identifier);
    00132           }
    00133         else if(identifier == "BUYDEBT" ||
    00134                 identifier == "BUYMF" ||
    00135                 identifier == "BUYOPT" ||
    00136                 identifier == "BUYOTHER" ||
    00137                 identifier == "BUYSTOCK" ||
    00138                 identifier == "CLOSUREOPT" ||
    00139                 identifier == "INCOME" ||
    00140                 identifier == "INVEXPENSE" ||
    00141                 identifier == "JRNLFUND" ||
    00142                 identifier == "JRNLSEC" ||
    00143                 identifier == "MARGININTEREST" ||
    00144                 identifier == "REINVEST" ||
    00145                 identifier == "RETOFCAP" ||
    00146                 identifier == "SELLDEBT" ||
    00147                 identifier == "SELLMF" ||
    00148                 identifier == "SELLOPT" ||
    00149                 identifier == "SELLOTHER" ||
    00150                 identifier == "SELLSTOCK" ||
    00151                 identifier == "SPLIT" ||
    00152                 identifier == "TRANSFER" )
    00153           {
    00154             message_out (PARSER, "Element " + identifier + " found");
    00155             curr_container_element = new OfxInvestmentTransactionContainer (libofx_context, curr_container_element, identifier);
    00156           }
    00157         /*The following is a list of OFX elements whose attributes will be processed by the parent container*/
    00158         else if (identifier == "INVBUY" ||
    00159                  identifier == "INVSELL" ||
    00160                  identifier == "INVTRAN" ||
    00161                  identifier == "SECID")
    00162           {
    00163             message_out (PARSER, "Element " + identifier + " found");
    00164             curr_container_element = new OfxPushUpContainer (libofx_context, curr_container_element, identifier);
    00165           }
    00166
    00167         /* The different types of accounts */
    00168         else if (identifier == "BANKACCTFROM" || identifier == "CCACCTFROM" || identifier == "INVACCTFROM")
    00169           {
    00170             message_out (PARSER, "Element " + identifier + " found");
    00171             curr_container_element = new OfxAccountContainer (libofx_context, curr_container_element, identifier);
    00172           }
    00173         else if (identifier == "SECINFO")
    00174           {
    00175             message_out (PARSER, "Element " + identifier + " found");
    00176             curr_container_element = new OfxSecurityContainer (libofx_context, curr_container_element, identifier);
    00177           }
    00178         /* The different types of balances */
    00179         else if (identifier == "LEDGERBAL" || identifier == "AVAILBAL")
    00180           {
    00181             message_out (PARSER, "Element " + identifier + " found");
    00182             curr_container_element = new OfxBalanceContainer (libofx_context, curr_container_element, identifier);
    00183           }
    00184         else
    00185           {
    00186             /* We dont know this OFX element, so we create a dummy container */
    00187             curr_container_element = new OfxDummyContainer(libofx_context, curr_container_element, identifier);
    00188           }
    00189       }
    00190     else
    00191       {
    00192         /* The element was a data element.  OpenSP will call one or several data() callback with the data */
    00193         message_out (PARSER, "Data element " + identifier + " found");
    00194         /* There is a bug in OpenSP 1.3.4, which won't send endElement Event for some elements, and will instead send an error like "document type does not allow element "MESSAGE" here".  Incoming_data should be empty in such a case, but it will not be if the endElement event was skiped. So we empty it, so at least the last element has a chance of having valid data */
    00195         if (incoming_data != "")
    00196           {
    00197             message_out (ERROR, "startElement: incoming_data should be empty! You are probably using OpenSP <= 1.3.4.  The folowing data was lost: " + incoming_data );
    00198             incoming_data.assign ("");
    00199           }
    00200       }
    00201   }
    00202
    00207   void endElement (const EndElementEvent & event)
    00208   {
    00209     string identifier;
    00210     bool end_element_for_data_element;
    00211
    00212     CharStringtostring (event.gi, identifier);
    00213     end_element_for_data_element=is_data_element;
    00214     message_out(PARSER,"endElement event received from OpenSP for element " + identifier);
    00215
    00216     position = event.pos;
    00217     if (curr_container_element == NULL)
    00218       {
    00219         message_out (ERROR,"Tried to close a "+identifier+" without a open element (NULL pointer)");
    00220         incoming_data.assign ("");
    00221       }
    00222     else //curr_container_element != NULL
    00223       {
    00224         if (end_element_for_data_element == true)
    00225           {
    00226             incoming_data = strip_whitespace(incoming_data);
    00227
    00228             curr_container_element->add_attribute (identifier, incoming_data);
    00229             message_out (PARSER,"endElement: Added data '" + incoming_data + "' from " + identifier + " to " + curr_container_element->type + " container_element");
    00230             incoming_data.assign ("");
    00231             is_data_element=false;
    00232           }
    00233         else
    00234           {
    00235             if (identifier == curr_container_element->tag_identifier)
    00236               {
    00237                 if(incoming_data!="")
    00238                   {
    00239                     message_out(ERROR,"End tag for non data element "+identifier+", incoming data should be empty but contains: "+incoming_data+" DATA HAS BEEN LOST SOMEWHERE!");
    00240                   }
    00241
    00242                 if(identifier == "OFX")
    00243                   {
    00244                     /* The main container is a special case */
    00245                     tmp_container_element = curr_container_element;
    00246                     curr_container_element = curr_container_element->getparent ();
    00247                     MainContainer->gen_event();
    00248                     delete MainContainer;
    00249                     MainContainer = NULL;
    00250                     message_out (DEBUG, "Element " + identifier + " closed, MainContainer destroyed");
    00251                   }
    00252                 else
    00253                   {
    00254                     tmp_container_element = curr_container_element;
    00255                     curr_container_element = curr_container_element->getparent ();
    00256                     if(MainContainer != NULL)
    00257                       {
    00258                         tmp_container_element->add_to_main_tree();
    00259                         message_out (PARSER, "Element " + identifier + " closed, object added to MainContainer");
    00260                       }
    00261                     else
    00262                       {
    00263                         message_out (ERROR, "MainContainer is NULL trying to add element " + identifier);
    00264                       }
    00265                   }
    00266               }
    00267             else
    00268               {
    00269                 message_out (ERROR, "Tried to close a "+identifier+" but a "+curr_container_element->type+" is currently open.");
    00270               }
    00271           }
    00272       }
    00273   }
    00274
    00279   void data (const DataEvent & event)
    00280   {
    00281     string tmp;
    00282     position = event.pos;
    00283     AppendCharStringtostring (event.data, incoming_data);
    00284     message_out(PARSER, "data event received from OpenSP, incoming_data is now: " + incoming_data);
    00285   }
    00286
    00291   void error (const ErrorEvent & event)
    00292   {
    00293     string message;
    00294     string string_buf;
    00295     OfxMsgType error_type = ERROR;
    00296
    00297     position = event.pos;
    00298     message = message + "OpenSP parser: ";
    00299     switch (event.type){
    00300     case SGMLApplication::ErrorEvent::quantity:
    00301       message = message + "quantity (Exceeding a quantity limit):";
    00302       error_type = ERROR;
    00303       break;
    00304     case SGMLApplication::ErrorEvent::idref:
    00305       message = message + "idref (An IDREF to a non-existent ID):";
    00306       error_type = ERROR;
    00307       break;
    00308     case SGMLApplication::ErrorEvent::capacity:
    00309       message = message + "capacity (Exceeding a capacity limit):";
    00310       error_type = ERROR;
    00311       break;
    00312     case SGMLApplication::ErrorEvent::otherError:
    00313       message = message + "otherError (misc parse error):";
    00314       error_type = ERROR;
    00315       break;
    00316     case SGMLApplication::ErrorEvent::warning:
    00317       message = message + "warning (Not actually an error.):";
    00318       error_type = WARNING;
    00319       break;
    00320     case SGMLApplication::ErrorEvent::info:
    00321       message =  message + "info (An informationnal message.  Not actually an error):";
    00322       error_type = INFO;
    00323       break;
    00324     default:
    00325       message = message + "OpenSP sent an unknown error to LibOFX (You probably have a newer version of OpenSP):";
    00326     }
    00327     message =   message + "\n" + CharStringtostring (event.message, string_buf);
    00328     message_out (error_type, message);
    00329   }
    00330
    00335   void openEntityChange (const OpenEntityPtr & para_entity_ptr)
    00336   {
    00337     message_out(DEBUG,"openEntityChange()\n");
    00338     entity_ptr = para_entity_ptr;
    00339
    00340   };
    00341
    00342 private:
    00343 };
    00344
    00348 int ofx_proc_sgml(LibofxContext * libofx_context, int argc, char *argv[])
    00349 {
    00350   message_out(DEBUG,"Begin ofx_proc_sgml()");
    00351   message_out(DEBUG,argv[0]);
    00352   message_out(DEBUG,argv[1]);
    00353   message_out(DEBUG,argv[2]);
    00354
    00355   ParserEventGeneratorKit parserKit;
    00356   parserKit.setOption (ParserEventGeneratorKit::showOpenEntities);
    00357   EventGenerator *egp = parserKit.makeEventGenerator (argc, argv);
    00358   egp->inhibitMessages (true);  /* Error output is handled by libofx not OpenSP */
    00359   OFXApplication *app = new OFXApplication(libofx_context);
    00360   unsigned nErrors = egp->run (*app); /* Begin parsing */
    00361   delete egp;
    00362   return nErrors > 0;
    00363 }