xmlwriter.h

00001 
00002 //
00003 // xmlwriter.h: interface & implementation for the XmlStream class.
00004 // 
00005 // Author: Oboltus, December 2003
00006 // see: http://www.codeproject.com/vcpp/stl/simple_xmlwriter.asp
00007 //
00008 // This code is provided "as is", with absolutely no warranty expressed
00009 // or implied. Any use is at your own risk.
00010 //
00011 // some code added by Bernd Speiser, 2005-2007 (see BS below)
00012 //
00014 
00015 #ifndef __XMLWRITER_H_2CC1D410_9DE8_4452_B8F0_F987EF152E06
00016 #define __XMLWRITER_H_2CC1D410_9DE8_4452_B8F0_F987EF152E06
00017 
00018 // disable terrible MSVC warnings which are issued when using STL
00019 #ifdef  _MSC_VER
00020 #pragma warning( disable : 4786 ) 
00021 #pragma warning( disable : 4514 )
00022 #endif
00023 
00024 #include        <stack>
00025 #include        <string>
00026 #include        <sstream>
00027 // added by BS to allow use of ofstream
00028 #include        <fstream>
00029 
00030 namespace BSUtilities {
00031 namespace xmlw {
00032 
00033 class XmlStream {
00034 public:
00035 
00036         // XML version constants
00037         enum {versionMajor = 1, versionMinor = 0};
00038 
00039         // Internal helper class
00040         struct Controller {
00041                 typedef enum {whatProlog, whatTag, whatTagEnd, whatAttribute, whatCharData}     what_type;
00042 
00043                 what_type       what;
00044                 std::string str;
00045 
00046                 inline Controller(const Controller& c) : what(c.what), str(c.str) {}
00047                 inline Controller(const what_type _what) : what(_what){}
00048                 
00049                 // use template constructor because string field <str> may be initialized 
00050                 // from different sources: char*, std::string etc
00051                 template<class t>
00052                 inline Controller(const what_type _what, const t& _str) : what(_what), str(_str) {}
00053         };
00054 
00055         // XmlStream refers std::ostream object to perform actual output operations
00056         inline XmlStream(std::ostream&  _s) : s(_s), state(stateNone), prologWritten(false) {}
00057 
00058         // Before destroying check whether all the open tags are closed
00059         ~XmlStream() {
00060                 if (stateTagName == state) {
00061                         s << "/>";
00062                         state = stateNone;
00063                 }
00064                 while (tags.size())
00065                         endTag(tags.top());
00066         }
00067 
00068         // default behaviour - delegate object output to std::stream
00069         template<class t>
00070         XmlStream& operator<<(const t& value) {
00071                 if (stateTagName == state)
00072                         tagName << value;
00073                 s << value;
00074                 return *this;
00075         }
00076 
00077         // this is the main working horse
00078         // and it's long a little
00079         XmlStream& operator<<(const Controller& controller) {
00080 
00081                 switch (controller.what) {
00082                 case Controller::whatProlog:
00083                         if (!prologWritten && stateNone == state) {
00084                                 s << "<?xml version=\"" << versionMajor << '.' << versionMinor << "\"?>\n";
00085                                 prologWritten = true;
00086                         }
00087                         break;  //      Controller::whatProlog
00088 
00089                 case Controller::whatTag:
00090                         closeTagStart();
00091                         s << '<';
00092                         if (controller.str.empty()) {
00093                                 clearTagName();
00094                                 state = stateTagName;
00095                         }
00096                         else {
00097                                 s << controller.str;
00098                                 tags.push(controller.str);
00099                                 state = stateTag;
00100                         }
00101                         break;  //      Controller::whatTag
00102 
00103                 case Controller::whatTagEnd:
00104                         endTag(controller.str);
00105                         break;  //      Controller::whatTagEnd
00106 
00107                 case Controller::whatAttribute:
00108                         switch (state) {
00109                         case stateTagName:
00110                                 tags.push(tagName.str());
00111                                 break;
00112 
00113                         case stateAttribute:
00114                                 s << '\"';
00115 // added default switch, BS
00116                         default:
00117                           ;
00118                         }
00119 
00120                         if (stateNone != state) {
00121                                 s << ' ' << controller.str << "=\"";
00122                                 state = stateAttribute;
00123                         }
00124                         // else throw some error - unexpected attribute (out of any tag)
00125 
00126                         break;  //      Controller::whatAttribute
00127 
00128                 case Controller::whatCharData:
00129                         closeTagStart();
00130                         state = stateNone;
00131                         break;  //      Controller::whatCharData
00132                 }
00133 
00134                 return  *this;
00135         }
00136 
00137 private:
00138         // state of the stream 
00139         typedef enum {stateNone, stateTag, stateAttribute, stateTagName}        state_type;
00140 
00141         // tag name stack
00142         typedef std::stack<std::string> tag_stack_type;
00143 
00144         tag_stack_type  tags;
00145 // exchanged the two following lines, BS
00146 // to avoid warning from gcc about initialization order
00147         std::ostream&   s;
00148         state_type      state;
00149         bool    prologWritten;
00150         std::ostringstream      tagName;
00151 
00152         // I don't know any way easier (legal) to clear std::stringstream...
00153         inline void clearTagName() {
00154                 const std::string       empty_str;
00155                 tagName.rdbuf()->str(empty_str);
00156         }
00157 
00158         // Close current tag
00159         void closeTagStart(bool self_closed = false) {
00160                 if (stateTagName == state)
00161                         tags.push(tagName.str());
00162 
00163                 // note: absence of 'break's is not an error
00164                 switch (state) {
00165                 case stateAttribute:
00166                         s << '\"';
00167 
00168                 case stateTagName:
00169                 case stateTag:
00170                         if (self_closed)
00171                                 s << '/';
00172 // added newline, BS
00173                         s << ">\n";
00174 // added default switch, BS
00175                 default:
00176                      ;
00177                 }
00178         }
00179 
00180         // Close tag (may be with closing all of its children)
00181         void endTag(const std::string& tag) {
00182                 bool    brk = false;
00183 
00184                 while (tags.size() > 0 && !brk) {
00185                         if (stateNone == state)
00186 // added newline, BS
00187                                 s << "</" << tags.top() << ">\n";
00188                         else {
00189                                 closeTagStart(true);
00190                                 state = stateNone;
00191                         }
00192                         brk = tag.empty() || tag == tags.top();
00193                         tags.pop();
00194                 }
00195         }
00196 };      //      class XmlStream
00197 
00198 // Helper functions, they may be simply overwritten
00199 // E.g. you may use std::string instead of const char*
00200 
00201 inline const XmlStream::Controller prolog() {
00202 return XmlStream::Controller(XmlStream::Controller::whatProlog);
00203 }
00204 
00205 inline const XmlStream::Controller tag() {
00206 return XmlStream::Controller(XmlStream::Controller::whatTag);
00207 }
00208 
00209 inline const XmlStream::Controller tag(const char* const tag_name) {
00210  return XmlStream::Controller(XmlStream::Controller::whatTag, tag_name);
00211 }
00212 
00213 //BS, 08.11.2005
00214 inline const XmlStream::Controller tag(const std::string tag_name) {
00215  return XmlStream::Controller(XmlStream::Controller::whatTag, 
00216                                                       tag_name.c_str());
00217 }
00218 
00219 inline const XmlStream::Controller endtag() {
00220         return XmlStream::Controller(XmlStream::Controller::whatTagEnd);
00221 }
00222 
00223 inline const XmlStream::Controller endtag(const char* const tag_name) {
00224  return 
00225      XmlStream::Controller(XmlStream::Controller::whatTagEnd, tag_name);
00226 }
00227 
00228 //BS, 08.11.2005
00229 inline const XmlStream::Controller endtag(const std::string tag_name) {
00230  return XmlStream::Controller(XmlStream::Controller::whatTagEnd, 
00231                                                       tag_name.c_str());
00232 }
00233 
00234 inline const XmlStream::Controller attr(const char* const attr_name) {
00235  return XmlStream::Controller(XmlStream::Controller::whatAttribute, 
00236                                                              attr_name);
00237 }
00238 
00239 //BS, 08.11.2005
00240 inline const XmlStream::Controller attr(const std::string attr_name) {
00241  return XmlStream::Controller(XmlStream::Controller::whatAttribute, 
00242                                                      attr_name.c_str());
00243 }
00244 
00245 inline const XmlStream::Controller chardata() {
00246       return XmlStream::Controller(XmlStream::Controller::whatCharData);
00247 }
00248 
00250 
00258 template<class X>
00259   void save (const std::string &filename, const X obj)
00260   {
00261     std::ofstream save_file (filename.c_str());
00262     if (save_file)
00263     {
00264       xmlw::XmlStream stream (save_file);
00265       stream << xmlw::prolog ();
00266       
00267       obj.save (stream);
00268 
00269       save_file.close ();
00270     }
00271   }
00272 
00273 }       // end namespace xmlw
00274 }       // end namespace BSUtilities
00275 
00276 #endif  //  __XMLWRITER_H_2CC1D410_9DE8_4452_B8F0_F987EF152E06

Generated on Sun Jul 26 16:51:58 2009 for BSUtilities by  doxygen 1.5.3