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

Generated on Fri Sep 12 00:35:47 2003 for LibOFX by doxygen 1.3.3