// file : examples/cxx/hybrid/multiroot/driver.cxx // author : Boris Kolpackov // copyright : not copyrighted - public domain #include #include "protocol.hxx" #include "protocol-pimpl.hxx" using namespace std; using xml_schema::ro_string; using xml_schema::parser_error; parser_error pe; namespace protocol { // We are going to use our own "type ids" for the request types. // enum request_type { unknown_type, balance_type, withdraw_type }; // Customize the xml_schema::document_pimpl object to handle our protocol // vocabulary with multiple root elements. // class document_pimpl: public xml_schema::document_pimpl { public: document_pimpl () : result_type_ (unknown_type) { } request_type result_type () const { return result_type_; } protocol::balance balance () const { return balance_; } protocol::withdraw withdraw () const { return withdraw_; } protected: // This function is called to obtain the root element type parser. // If the returned pointed is 0 then the whole document content // is ignored. Note that the signature of this function varies // depending on whether the runtime was built with polymorphism // support. // virtual xml_schema::parser_base* #ifndef XSDE_POLYMORPHIC start_root_element (const ro_string& ns, const ro_string& name) #else start_root_element (const ro_string& ns, const ro_string& name, const char* /* xsi:type */) #endif { if (ns == "http://www.codesynthesis.com/protocol") { if (name == balance_p_.root_name ()) { balance_p_.pre (); pe = balance_p_._error (); if (pe) printf( " parse error after PRE() \n\n"); return &balance_p_.root_parser (); } else if (name == "withdraw") { balance_p_.pre (); pe = balance_p_._error (); if (pe) printf( " parse error after PRE() \n\n"); return &withdraw_p_.root_parser (); } // Ignore unknown request. // return 0; } else { // This document is from the wrong namespace. If the runtime and // the generated code are built with validation enabled then we // can set an XML Schema error. Otherwise, we ignore it. // #ifdef XSDE_PARSER_VALIDATION context_.schema_error ( xml_schema::parser_schema_error::unexpected_element); #endif return 0; } } // This function is called to indicate the completion of document // parsing. The parser argument contains the pointer returned by // start_root_element. // virtual void end_root_element (const ro_string& /* ns */, const ro_string& /* name */, xml_schema::parser_base* parser) { // We could have handled the result directly in this function // instead of storing it in the result variables. // if (parser == &balance_p_.root_parser ()) { result_type_ = balance_type; balance_ = balance_p_.post (); pe = balance_p_._error (); if (pe) printf( " parse error after POST() \n\n"); } else if (parser == &withdraw_p_.root_parser ()) { result_type_ = withdraw_type; withdraw_ = withdraw_p_.post (); pe = withdraw_p_._error (); } else result_type_ = unknown_type; } public: // If we need to be able to reset and reuse the parser after // an error then we also need to override reset() and reset // the root parsers. We can also get smarter here by caching // the parser that was used last and only reset that. Note // that you always need to call _reset() from the base. // virtual void reset () { xml_schema::document_pimpl::reset (); balance_p_.reset (); withdraw_p_.reset (); } private: // Result. // request_type result_type_; protocol::balance balance_; protocol::withdraw withdraw_; // Parsers for various root elements. // balance_paggr balance_p_; withdraw_paggr withdraw_p_; }; } int main (int argc, char* argv[]) { const char* input; // input file name char buf[4096] ; input = argv[1]; // Open the file // FILE* f = fopen (input, "rb"); // Read the contents of the file into the buffer size_t s = fread (buf, 1, sizeof (buf), f); // Print out the size and contents of the file printf( " number of bytes in the file = %d\n\n", s); printf( "%s\n", buf); using namespace protocol; // Check if the file read failed. int fe = ferror (f); if (s != sizeof (buf) && fe) { printf( " size s = %d ferror = %d \n", s,fe ); return 1; } // Parse. // document_pimpl doc_p; // pre() and post() are called as part of the start_root_element() // and end_root_element() calls. // // parse (const void* data, size_t size, bool last) doc_p.parse ( buf, sizeof(buf), true ); pe = doc_p._error (); printf( " finished parsing \n\n"); printf(" paser error = %d\n", pe); // Parser error, determine the type, print out error contents, fail program. if (pe) { switch (pe.type ()) { case parser_error::sys: { fprintf (stderr, "%parser sys s: %s\n", input, pe.sys_text ()); break; } case parser_error::xml: { fprintf (stderr, "xml %s:%lu:%lu: %s\n", input, pe.line (), pe.column (), pe.xml_text ()); break; } #ifdef XSDE_PARSER_VALIDATION case parser_error::schema: { fprintf (stderr, "parser %s:%lu:%lu: %s\n", input, pe.line (), pe.column (), pe.schema_text ()); break; } #endif case parser_error::app: { fprintf (stderr, "app %s:%lu:%lu: application error %d\n", input, pe.line (), pe.column (), pe.app_code ()); break; } default: break; } // return 1; // Is 1 considered an error. Can I return true vs false? } // Print what we've got. // switch (doc_p.result_type ()) { case balance_type: { balance b (doc_p.balance ()); cerr << "balance request for acc# " << b.account () << endl; break; } case withdraw_type: { withdraw w (doc_p.withdraw ()); cerr << "withdrawal request for acc# " << w.account () << ", " << "amount: " << w.amount () << endl; break; } case unknown_type: { cerr << "unknown request" << endl; break; } } return 0; // Okay? }