LibOFX

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                : benoitg@coeus.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 {
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 public:
00053   OFCApplication (LibofxContext * p_libofx_context)
00054   {
00055     MainContainer = NULL;
00056     curr_container_element = NULL;
00057     is_data_element = false;
00058     libofx_context = p_libofx_context;
00059   }
00060 
00065   void startElement (const StartElementEvent & event)
00066   {
00067     string identifier;
00068     CharStringtostring (event.gi, identifier);
00069     message_out(PARSER, "startElement event received from OpenSP for element " + identifier);
00070 
00071     position = event.pos;
00072 
00073     switch (event.contentType)
00074     {
00075     case StartElementEvent::empty:
00076       message_out(ERROR, "StartElementEvent::empty\n");
00077       break;
00078     case StartElementEvent::cdata:
00079       message_out(ERROR, "StartElementEvent::cdata\n");
00080       break;
00081     case StartElementEvent::rcdata:
00082       message_out(ERROR, "StartElementEvent::rcdata\n");
00083       break;
00084     case StartElementEvent::mixed:
00085       message_out(PARSER, "StartElementEvent::mixed");
00086       is_data_element = true;
00087       break;
00088     case StartElementEvent::element:
00089       message_out(PARSER, "StartElementEvent::element");
00090       is_data_element = false;
00091       break;
00092     default:
00093       message_out(ERROR, "Unknow SGML content type?!?!?!? OpenSP interface changed?");
00094     }
00095 
00096     if (is_data_element == false)
00097     {
00098       /*------- The following are OFC entities ---------------*/
00099 
00100       if (identifier == "OFC")
00101       {
00102         message_out (PARSER, "Element " + identifier + " found");
00103         MainContainer = new OfxMainContainer (libofx_context, curr_container_element, identifier);
00104         curr_container_element = MainContainer;
00105       }
00106       else if (identifier == "STATUS")
00107       {
00108         message_out (PARSER, "Element " + identifier + " found");
00109         curr_container_element = new OfxStatusContainer (libofx_context, curr_container_element, identifier);
00110       }
00111       else if (identifier == "ACCTSTMT")
00112       {
00113         message_out (PARSER, "Element " + identifier + " found");
00114         curr_container_element = new OfxStatementContainer (libofx_context, curr_container_element, identifier);
00115       }
00116       else if (identifier == "STMTRS")
00117       {
00118         message_out (PARSER, "Element " + identifier + " found");
00119         //STMTRS ignored, we will process it's attributes directly inside the STATEMENT,
00120         if (curr_container_element->type != "STATEMENT")
00121         {
00122           message_out(ERROR, "Element " + identifier + " found while not inside a STATEMENT container");
00123         }
00124         else
00125         {
00126           curr_container_element = new OfxPushUpContainer (libofx_context, curr_container_element, identifier);
00127         }
00128       }
00129       else if (identifier == "GENTRN" ||
00130                identifier == "STMTTRN")
00131       {
00132         message_out (PARSER, "Element " + identifier + " found");
00133         curr_container_element = new OfxBankTransactionContainer (libofx_context, curr_container_element, identifier);
00134       }
00135       else if (identifier == "BUYDEBT" ||
00136                identifier == "BUYMF" ||
00137                identifier == "BUYOPT" ||
00138                identifier == "BUYOTHER" ||
00139                identifier == "BUYSTOCK" ||
00140                identifier == "CLOSUREOPT" ||
00141                identifier == "INCOME" ||
00142                identifier == "INVEXPENSE" ||
00143                identifier == "JRNLFUND" ||
00144                identifier == "JRNLSEC" ||
00145                identifier == "MARGININTEREST" ||
00146                identifier == "REINVEST" ||
00147                identifier == "RETOFCAP" ||
00148                identifier == "SELLDEBT" ||
00149                identifier == "SELLMF" ||
00150                identifier == "SELLOPT" ||
00151                identifier == "SELLOTHER" ||
00152                identifier == "SELLSTOCK" ||
00153                identifier == "SPLIT" ||
00154                identifier == "TRANSFER" )
00155       {
00156         message_out (PARSER, "Element " + identifier + " found");
00157         curr_container_element = new OfxInvestmentTransactionContainer (libofx_context, curr_container_element, identifier);
00158       }
00159       /*The following is a list of OFX elements whose attributes will be processed by the parent container*/
00160       else if (identifier == "INVBUY" ||
00161                identifier == "INVSELL" ||
00162                identifier == "INVTRAN" ||
00163                identifier == "SECID")
00164       {
00165         message_out (PARSER, "Element " + identifier + " found");
00166         curr_container_element = new OfxPushUpContainer (libofx_context, curr_container_element, identifier);
00167       }
00168 
00169       /* The different types of accounts */
00170       else if (identifier == "ACCOUNT" ||
00171                identifier == "ACCTFROM" )
00172       {
00173         message_out (PARSER, "Element " + identifier + " found");
00174         curr_container_element = new OfxAccountContainer (libofx_context, curr_container_element, identifier);
00175       }
00176       else if (identifier == "SECINFO")
00177       {
00178         message_out (PARSER, "Element " + identifier + " found");
00179         curr_container_element = new OfxSecurityContainer (libofx_context, curr_container_element, identifier);
00180       }
00181       /* The different types of balances */
00182       else if (identifier == "LEDGERBAL" || identifier == "AVAILBAL")
00183       {
00184         message_out (PARSER, "Element " + identifier + " found");
00185         curr_container_element = new OfxBalanceContainer (libofx_context, curr_container_element, identifier);
00186       }
00187       else
00188       {
00189         /* We dont know this OFX element, so we create a dummy container */
00190         curr_container_element = new OfxDummyContainer(libofx_context, curr_container_element, identifier);
00191       }
00192     }
00193     else
00194     {
00195       /* The element was a data element.  OpenSP will call one or several data() callback with the data */
00196       message_out (PARSER, "Data element " + identifier + " found");
00197       /* 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 */
00198       if (incoming_data != "")
00199       {
00200         message_out (ERROR, "startElement: incoming_data should be empty! You are probably using OpenSP <= 1.3.4.  The folowing data was lost: " + incoming_data );
00201         incoming_data.assign ("");
00202       }
00203     }
00204   }
00205 
00210   void endElement (const EndElementEvent & event)
00211   {
00212     string identifier;
00213     bool end_element_for_data_element;
00214 
00215     CharStringtostring (event.gi, identifier);
00216     end_element_for_data_element = is_data_element;
00217     message_out(PARSER, "endElement event received from OpenSP for element " + identifier);
00218 
00219     position = event.pos;
00220     if (curr_container_element == NULL)
00221     {
00222       message_out (ERROR, "Tried to close a " + identifier + " without a open element (NULL pointer)");
00223       incoming_data.assign ("");
00224     }
00225     else     //curr_container_element != NULL
00226     {
00227       if (end_element_for_data_element == true)
00228       {
00229         incoming_data = strip_whitespace(incoming_data);
00230 
00231         curr_container_element->add_attribute (identifier, incoming_data);
00232         message_out (PARSER, "endElement: Added data '" + incoming_data + "' from " + identifier + " to " + curr_container_element->type + " container_element");
00233         incoming_data.assign ("");
00234         is_data_element = false;
00235       }
00236       else
00237       {
00238         if (identifier == curr_container_element->tag_identifier)
00239         {
00240           if (incoming_data != "")
00241           {
00242             message_out(ERROR, "End tag for non data element " + identifier + ", incoming data should be empty but contains: " + incoming_data + " DATA HAS BEEN LOST SOMEWHERE!");
00243           }
00244 
00245           if (identifier == "OFX")
00246           {
00247             /* The main container is a special case */
00248             tmp_container_element = curr_container_element;
00249             curr_container_element = curr_container_element->getparent ();
00250             MainContainer->gen_event();
00251             delete MainContainer;
00252             MainContainer = NULL;
00253             message_out (DEBUG, "Element " + identifier + " closed, MainContainer destroyed");
00254           }
00255           else
00256           {
00257             tmp_container_element = curr_container_element;
00258             curr_container_element = curr_container_element->getparent ();
00259             if (MainContainer != NULL)
00260             {
00261               tmp_container_element->add_to_main_tree();
00262               message_out (PARSER, "Element " + identifier + " closed, object added to MainContainer");
00263             }
00264             else
00265             {
00266               message_out (ERROR, "MainContainer is NULL trying to add element " + identifier);
00267             }
00268           }
00269         }
00270         else
00271         {
00272           message_out (ERROR, "Tried to close a " + identifier + " but a " + curr_container_element->type + " is currently open.");
00273         }
00274       }
00275     }
00276   }
00277 
00282   void data (const DataEvent & event)
00283   {
00284     string tmp;
00285     position = event.pos;
00286     AppendCharStringtostring (event.data, incoming_data);
00287     message_out(PARSER, "data event received from OpenSP, incoming_data is now: " + incoming_data);
00288   }
00289 
00294   void error (const ErrorEvent & event)
00295   {
00296     string message;
00297     string string_buf;
00298     OfxMsgType error_type = ERROR;
00299 
00300     position = event.pos;
00301     message = message + "OpenSP parser: ";
00302     switch (event.type)
00303     {
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 ofc_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   OFCApplication *app = new OFCApplication(libofx_context);
00364   unsigned nErrors = egp->run (*app); /* Begin parsing */
00365   delete egp;
00366   return nErrors > 0;
00367 }