Main Page | Class Hierarchy | Class List | File List | Class Members | Related Pages

descriptor/src/XmlWriter.h

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

Generated on Fri May 19 23:12:36 2006 for common by  doxygen 1.4.4