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

Generated on Wed Jan 14 20:18:06 2004 for LibOFX by doxygen 1.3.3