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

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