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   ~OFXApplication()
00063   {
00064     message_out(DEBUG,"Entering the OFXApplication's destructor");
00065   }
00066   
00071   void startElement (const StartElementEvent & event)
00072   {
00073     string identifier;
00074     CharStringtostring (event.gi, identifier);
00075     message_out(PARSER,"startElement event received from OpenSP for element " + identifier);
00076     
00077     position = event.pos;
00078 
00079     switch (event.contentType)
00080       {
00081       case StartElementEvent::empty:    message_out(ERROR,"StartElementEvent::empty\n");
00082         break;
00083       case StartElementEvent::cdata:    message_out(ERROR,"StartElementEvent::cdata\n");
00084         break;
00085       case StartElementEvent::rcdata:   message_out(ERROR,"StartElementEvent::rcdata\n");
00086         break;
00087       case StartElementEvent::mixed:    message_out(PARSER,"StartElementEvent::mixed");
00088         is_data_element = true;
00089         break;
00090       case StartElementEvent::element:  message_out(PARSER,"StartElementEvent::element");
00091         is_data_element = false;
00092         break;
00093       default:
00094         message_out(ERROR,"Unknow SGML content type?!?!?!? OpenSP interface changed?");
00095       }
00096     
00097     if (is_data_element == false)
00098       {
00099         /*------- The following are OFX entities ---------------*/
00100 
00101         if (identifier == "OFX")
00102           {
00103             message_out (PARSER, "Element " + identifier + " found");
00104             MainContainer = new OfxMainContainer (libofx_context, curr_container_element, identifier);
00105             curr_container_element = MainContainer;
00106           }
00107         else if (identifier == "STATUS")
00108           {
00109             message_out (PARSER, "Element " + identifier + " found");
00110             curr_container_element = new OfxStatusContainer (libofx_context, curr_container_element, identifier);
00111           }
00112         else if (identifier == "STMTRS" ||
00113                  identifier == "CCSTMTRS" ||
00114                  identifier == "INVSTMTRS")
00115           {
00116             message_out (PARSER, "Element " + identifier + " found");
00117             curr_container_element = new OfxStatementContainer (libofx_context, curr_container_element, identifier);
00118           }
00119         else if (identifier == "BANKTRANLIST")
00120           {
00121             message_out (PARSER, "Element " + identifier + " found");
00122             //BANKTRANLIST ignored, we will process it's attributes directly inside the STATEMENT,
00123             if(curr_container_element->type!="STATEMENT")
00124               {
00125                 message_out(ERROR,"Element " + identifier + " found while not inside a STATEMENT container");
00126               }
00127             else
00128               {
00129                 curr_container_element = new OfxPushUpContainer (libofx_context, curr_container_element, identifier);
00130               }
00131           }
00132         else if (identifier == "STMTTRN")
00133           {
00134             message_out (PARSER, "Element " + identifier + " found");
00135             curr_container_element = new OfxBankTransactionContainer (libofx_context, curr_container_element, identifier);
00136           }
00137         else if(identifier == "BUYDEBT" ||
00138                 identifier == "BUYMF" ||
00139                 identifier == "BUYOPT" ||
00140                 identifier == "BUYOTHER" ||
00141                 identifier == "BUYSTOCK" ||
00142                 identifier == "CLOSUREOPT" ||
00143                 identifier == "INCOME" ||
00144                 identifier == "INVEXPENSE" ||
00145                 identifier == "JRNLFUND" ||
00146                 identifier == "JRNLSEC" ||
00147                 identifier == "MARGININTEREST" ||
00148                 identifier == "REINVEST" ||
00149                 identifier == "RETOFCAP" ||
00150                 identifier == "SELLDEBT" ||
00151                 identifier == "SELLMF" ||
00152                 identifier == "SELLOPT" ||
00153                 identifier == "SELLOTHER" ||
00154                 identifier == "SELLSTOCK" ||
00155                 identifier == "SPLIT" ||
00156                 identifier == "TRANSFER" )
00157           {
00158             message_out (PARSER, "Element " + identifier + " found");
00159             curr_container_element = new OfxInvestmentTransactionContainer (libofx_context, curr_container_element, identifier);
00160           }
00161         /*The following is a list of OFX elements whose attributes will be processed by the parent container*/
00162         else if (identifier == "INVBUY" ||
00163                  identifier == "INVSELL" ||
00164                  identifier == "INVTRAN" ||
00165                  identifier == "SECID")
00166           {
00167             message_out (PARSER, "Element " + identifier + " found");
00168             curr_container_element = new OfxPushUpContainer (libofx_context, curr_container_element, identifier);
00169           }
00170 
00171         /* The different types of accounts */
00172         else if (identifier == "BANKACCTFROM" || identifier == "CCACCTFROM" || identifier == "INVACCTFROM")
00173           {
00174             message_out (PARSER, "Element " + identifier + " found");
00175             curr_container_element = new OfxAccountContainer (libofx_context, curr_container_element, identifier);
00176           }
00177         else if (identifier == "SECINFO")
00178           {
00179             message_out (PARSER, "Element " + identifier + " found");
00180             curr_container_element = new OfxSecurityContainer (libofx_context, curr_container_element, identifier);
00181           }
00182         /* The different types of balances */
00183         else if (identifier == "LEDGERBAL" || identifier == "AVAILBAL")
00184           {
00185             message_out (PARSER, "Element " + identifier + " found");
00186             curr_container_element = new OfxBalanceContainer (libofx_context, curr_container_element, identifier);
00187           }
00188         else
00189           {
00190             /* We dont know this OFX element, so we create a dummy container */
00191             curr_container_element = new OfxDummyContainer(libofx_context, curr_container_element, identifier);
00192           }
00193       }
00194     else
00195       {
00196         /* The element was a data element.  OpenSP will call one or several data() callback with the data */
00197         message_out (PARSER, "Data element " + identifier + " found");
00198         /* 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 */ 
00199         if (incoming_data != "")
00200           {
00201             message_out (ERROR, "startElement: incoming_data should be empty! You are probably using OpenSP <= 1.3.4.  The folowing data was lost: " + incoming_data );
00202             incoming_data.assign ("");
00203           }
00204       }
00205   }
00206 
00211   void endElement (const EndElementEvent & event)
00212   {
00213     string identifier;
00214     bool end_element_for_data_element;
00215 
00216     CharStringtostring (event.gi, identifier);
00217     end_element_for_data_element=is_data_element;
00218     message_out(PARSER,"endElement event received from OpenSP for element " + identifier);
00219 
00220     position = event.pos;
00221     if (curr_container_element == NULL)
00222       {
00223         message_out (ERROR,"Tried to close a "+identifier+" without a open element (NULL pointer)");
00224         incoming_data.assign ("");
00225       }
00226     else //curr_container_element != NULL
00227       {
00228         if (end_element_for_data_element == true)
00229           {
00230             incoming_data = strip_whitespace(incoming_data);
00231             
00232             curr_container_element->add_attribute (identifier, incoming_data);
00233             message_out (PARSER,"endElement: Added data '" + incoming_data + "' from " + identifier + " to " + curr_container_element->type + " container_element");
00234             incoming_data.assign ("");
00235             is_data_element=false;
00236           }
00237         else
00238           {
00239             if (identifier == curr_container_element->tag_identifier)
00240               {
00241                 if(incoming_data!="")
00242                   {
00243                     message_out(ERROR,"End tag for non data element "+identifier+", incoming data should be empty but contains: "+incoming_data+" DATA HAS BEEN LOST SOMEWHERE!");
00244                   }
00245 
00246                 if(identifier == "OFX")
00247                   {
00248                     /* The main container is a special case */
00249                     tmp_container_element = curr_container_element;
00250                     curr_container_element = curr_container_element->getparent ();
00251                     MainContainer->gen_event();
00252                     delete MainContainer;
00253                     MainContainer = NULL;
00254                     message_out (DEBUG, "Element " + identifier + " closed, MainContainer destroyed");
00255                   }
00256                 else 
00257                   {
00258                     tmp_container_element = curr_container_element;
00259                     curr_container_element = curr_container_element->getparent ();
00260                     if(MainContainer != NULL)
00261                       {
00262                         tmp_container_element->add_to_main_tree();
00263                         message_out (PARSER, "Element " + identifier + " closed, object added to MainContainer");
00264                       }
00265                     else
00266                       {
00267                         message_out (ERROR, "MainContainer is NULL trying to add element " + identifier);
00268                       }
00269                   }
00270               }
00271             else
00272               {
00273                 message_out (ERROR, "Tried to close a "+identifier+" but a "+curr_container_element->type+" is currently open.");
00274               }
00275           }
00276       }
00277   }
00278   
00283   void data (const DataEvent & event)
00284   {
00285     string tmp;
00286     position = event.pos;
00287     AppendCharStringtostring (event.data, incoming_data);
00288     message_out(PARSER, "data event received from OpenSP, incoming_data is now: " + incoming_data);
00289   }
00290 
00295   void error (const ErrorEvent & event)
00296   {
00297     string message;
00298     string string_buf;
00299     OfxMsgType error_type = ERROR;
00300 
00301     position = event.pos;
00302     message = message + "OpenSP parser: ";
00303     switch (event.type){
00304     case SGMLApplication::ErrorEvent::quantity:
00305       message = message + "quantity (Exceeding a quantity limit):";
00306       error_type = ERROR;
00307       break;
00308     case SGMLApplication::ErrorEvent::idref:
00309       message = message + "idref (An IDREF to a non-existent ID):";
00310       error_type = ERROR;
00311       break;
00312     case SGMLApplication::ErrorEvent::capacity:
00313       message = message + "capacity (Exceeding a capacity limit):";
00314       error_type = ERROR;
00315       break;
00316     case SGMLApplication::ErrorEvent::otherError:
00317       message = message + "otherError (misc parse error):";
00318       error_type = ERROR;
00319       break;
00320     case SGMLApplication::ErrorEvent::warning:
00321       message = message + "warning (Not actually an error.):";
00322       error_type = WARNING;
00323       break;
00324     case SGMLApplication::ErrorEvent::info:
00325       message =  message + "info (An informationnal message.  Not actually an error):";
00326       error_type = INFO;
00327       break;
00328     default:
00329       message = message + "OpenSP sent an unknown error to LibOFX (You probably have a newer version of OpenSP):";
00330     }
00331     message =   message + "\n" + CharStringtostring (event.message, string_buf);
00332     message_out (error_type, message);
00333   }
00334 
00339   void openEntityChange (const OpenEntityPtr & para_entity_ptr)
00340   {
00341     message_out(DEBUG,"openEntityChange()\n");
00342     entity_ptr = para_entity_ptr;
00343 
00344   };
00345 
00346 private:
00347 };
00348 
00352 int ofx_proc_sgml(LibofxContext * libofx_context, int argc, char *argv[])
00353 {
00354   message_out(DEBUG,"Begin ofx_proc_sgml()");
00355   message_out(DEBUG,argv[0]);
00356   message_out(DEBUG,argv[1]);
00357   message_out(DEBUG,argv[2]);
00358   
00359   ParserEventGeneratorKit parserKit;
00360   parserKit.setOption (ParserEventGeneratorKit::showOpenEntities);
00361   EventGenerator *egp = parserKit.makeEventGenerator (argc, argv);
00362   egp->inhibitMessages (true);  /* Error output is handled by libofx not OpenSP */
00363   OFXApplication *app = new OFXApplication(libofx_context);
00364   unsigned nErrors = egp->run (*app); /* Begin parsing */
00365   delete egp;  //Note that this is where bug is triggered
00366   return nErrors > 0;
00367 }

Generated on Mon Feb 9 21:21:59 2009 for LibOFX by  doxygen 1.5.0