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

fx-0.8.0/lib/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 }

Generated on Sun Jul 31 15:38:35 2005 for LibOFX by  doxygen 1.3.9.1