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 #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 Fri Oct 8 20:34:48 2004 for LibOFX by doxygen 1.3.7