contrib/brl/bbas/bxml/bxml_read.cxx
Go to the documentation of this file.
00001 // This is brl/bbas/bxml/bxml_read.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \author Matt Leotta
00008 // \date   October 5, 2006
00009 
00010 #include "bxml_read.h"
00011 #include <vcl_deque.h>
00012 #include <vcl_utility.h>
00013 #include <vcl_fstream.h>
00014 #include <vcl_cassert.h>
00015 #include <vul/vul_file.h>
00016 #ifdef WIN32
00017  #define _LIB
00018 #endif
00019 #include <expatpp.h>
00020 
00021 // anonymous namespace
00022 namespace {
00023 
00024 class bxml_expat_parser : public expatpp
00025 {
00026  public:
00027   bxml_expat_parser(bool online = false) : online_mode_(online) {}
00028   virtual void startElement(const XML_Char* name, const XML_Char** atts);
00029   virtual void endElement(const XML_Char* name);
00030   virtual void charData(const XML_Char*, int len);
00031   virtual void xmlDecl( const XML_Char *version,
00032                         const XML_Char *encoding,
00033                         int            standalone);
00034 
00035   bxml_document document() const { return document_; }
00036 
00037   bool pop_complete_data(bxml_data_sptr& data, unsigned int& depth);
00038 
00039  private:
00040   bool online_mode_;
00041   vcl_vector<bxml_data_sptr> stack_;
00042   vcl_deque<vcl_pair<bxml_data_sptr,unsigned int> > complete_;
00043   bxml_document document_;
00044 };
00045 
00046 bool bxml_expat_parser::pop_complete_data(bxml_data_sptr& data, unsigned int& depth)
00047 {
00048   if (complete_.empty())
00049     return false;
00050 
00051   data = complete_.front().first;
00052   depth = complete_.front().second;
00053   complete_.pop_front();
00054   return true;
00055 }
00056 
00057 
00058 //: Handle the start of elements
00059 void bxml_expat_parser::startElement(const XML_Char* name, const XML_Char** atts)
00060 {
00061   bxml_element* element = new bxml_element(name);
00062   bxml_data_sptr data(element);
00063   // set all the attributes
00064   for (int i=0; atts[i]; i+=2) {
00065     element->set_attribute(atts[i],atts[i+1]);
00066   }
00067 
00068   // add this element to the current element or document
00069   if (stack_.empty()) {
00070     if (!online_mode_) {
00071       document_.set_root_element(data);
00072       stack_.push_back(data);
00073     }
00074     else
00075       stack_.push_back(NULL);
00076   }
00077   else{
00078     if (stack_.back().ptr()) {
00079       bxml_element* parent = static_cast<bxml_element*>(stack_.back().ptr());
00080       parent->append_data(data);
00081     }
00082     stack_.push_back(data);
00083   }
00084 }
00085 
00086 
00087 //: Handle the start of elements
00088 void bxml_expat_parser::endElement(const XML_Char* name)
00089 {
00090   if (stack_.back().ptr()) {
00091     assert(static_cast<bxml_element*>(stack_.back().ptr())->name() == vcl_string(name));
00092     complete_.push_back(vcl_pair<bxml_data_sptr,unsigned int>(stack_.back(),stack_.size()-1));
00093   }
00094   stack_.pop_back();
00095 }
00096 
00097 
00098 //: Handle character data
00099 void bxml_expat_parser::charData(const XML_Char* text, int len)
00100 {
00101   assert(!stack_.empty());
00102   if (stack_.back().ptr()) {
00103     bxml_element* parent = static_cast<bxml_element*>(stack_.back().ptr());
00104     parent->append_text(vcl_string(text,len));
00105   }
00106 }
00107 
00108 
00109 //: Handle the XML declaration
00110 void bxml_expat_parser::xmlDecl( const XML_Char *version,
00111                                  const XML_Char *encoding,
00112                                  int            standalone)
00113 {
00114   document_.set_version(version);
00115   document_.set_encoding(encoding);
00116   document_.set_standalone(standalone != 0);
00117 }
00118 
00119 }; // end anonymous namespace
00120 
00121 
00122 //: Read the entire contents of \p filepath into an XML document class
00123 bxml_document bxml_read(const vcl_string& filepath)
00124 {
00125   if (!vul_file::exists(filepath))
00126     vcl_cerr<< "In bxml_read: " << vul_file::get_cwd() << filepath << " does not exist\n";
00127   vcl_ifstream file(filepath.c_str());
00128   return bxml_read(file);
00129 }
00130 
00131 
00132 //: Read the entire data stream \p is into an XML document class
00133 bxml_document bxml_read(vcl_istream& is)
00134 {
00135   bxml_expat_parser parser;
00136 
00137   char buf[4096];
00138   //char buf[9096];
00139   int done;
00140 
00141   while (is.good()) {
00142     is.get(buf,sizeof(buf),0);
00143     unsigned int n = is.gcount();
00144 
00145     done = (n+1 < sizeof(buf)) ? 1 : 0;
00146 
00147     if (parser.XML_Parse(buf,n,done) != XML_STATUS_OK ) {
00148       vcl_cerr << "Error parsing\n";
00149       break;
00150     }
00151   }
00152   return parser.document();
00153 }
00154 
00155 
00156 class bxml_stream_read::pimpl
00157 {
00158  public:
00159   pimpl(unsigned int max_depth) : parser(true), depth(max_depth) {}
00160 
00161   bxml_expat_parser parser;
00162   unsigned int depth;
00163 };
00164 
00165 //: Constructor
00166 bxml_stream_read::bxml_stream_read(int max_depth)
00167   : p_(new pimpl(max_depth))
00168 {
00169 }
00170 
00171 //: Destructor
00172 bxml_stream_read::~bxml_stream_read()
00173 {
00174   delete p_;
00175 }
00176 
00177 
00178 //: Reset the state of the reader
00179 void bxml_stream_read::reset()
00180 {
00181   if (p_) {
00182     unsigned int depth = p_->depth;
00183     delete p_;
00184     p_ = new pimpl(depth);
00185   }
00186 }
00187 
00188 
00189 //: Read the next element
00190 bxml_data_sptr
00191 bxml_stream_read::next_element(vcl_istream& is, unsigned int& depth)
00192 {
00193   char buf[4096];
00194   int done = 0;
00195 
00196   bxml_data_sptr data = NULL;
00197   depth = 0;
00198   while ( p_->parser.pop_complete_data(data, depth) )
00199     if (depth <= p_->depth)
00200       return data;
00201 
00202   while (is.good()){
00203     is.get(buf,sizeof(buf),0);
00204     int n = is.gcount();
00205     if (p_->parser.XML_Parse(buf,n,done) != XML_STATUS_OK ) {
00206       vcl_cerr << "Error parsing\n";
00207       break;
00208     }
00209 
00210     while ( p_->parser.pop_complete_data(data, depth) )
00211       if (depth <= p_->depth)
00212         return data;
00213   }
00214   return NULL;
00215 }
00216