source: GTP/trunk/App/Demos/Illum/pathmap/xmlwriter.h @ 2197

Revision 2197, 5.5 KB checked in by szirmay, 17 years ago (diff)
Line 
1//////////////////////////////////////////////////////////////////////
2//
3// xmlparser.h: interface & implementation for the XmlStream class.
4//
5// Author: Oboltus, December 2003
6//
7// This code is provided "as is", with absolutely no warranty expressed
8// or implied. Any use is at your own risk.
9//
10//////////////////////////////////////////////////////////////////////
11
12#ifndef __XMLWRITER_H_2CC1D410_9DE8_4452_B8F0_F987EF152E06
13#define __XMLWRITER_H_2CC1D410_9DE8_4452_B8F0_F987EF152E06
14
15// disable terrible MSVC warnings which are issued when using STL
16#ifdef  _MSC_VER
17#pragma warning( disable : 4786 )
18#pragma warning( disable : 4514 )
19#endif
20
21#include        <stack>
22#include        <string>
23#include        <sstream>
24
25namespace xmlw {
26
27class XmlStream {
28public:
29
30        // XML version constants
31        enum {versionMajor = 1, versionMinor = 0};
32
33        // Internal helper class
34        struct Controller {
35                typedef enum {whatProlog, whatTag, whatTagEnd, whatAttribute, whatCharData}     what_type;
36
37                what_type       what;
38                std::string str;
39
40                inline Controller(const Controller& c) : what(c.what), str(c.str) {}
41                inline Controller(const what_type _what) : what(_what){}
42               
43                // use template constructor because string field <str> may be initialized
44                // from different sources: char*, std::string etc
45                template<class t>
46                inline Controller(const what_type _what, const t& _str) : what(_what), str(_str) {}
47        };
48
49        // XmlStream refers std::ostream object to perform actual output operations
50        inline XmlStream(std::ostream&  _s) : s(_s), state(stateNone), prologWritten(false) {}
51
52        // Before destroying check whether all the open tags are closed
53        ~XmlStream() {
54                if (stateTagName == state) {
55                        s << "/>\n";
56                        state = stateNone;
57                }
58                while (tags.size())
59                        endTag(tags.top());
60        }
61
62        // default behaviour - delegate object output to std::stream
63        template<class t>
64        XmlStream& operator<<(const t& value) {
65                if (stateTagName == state)
66                        tagName << value;
67                s << value;
68                return *this;
69        }
70
71        // this is the main working horse
72        // and it's long a little
73        XmlStream& operator<<(const Controller& controller) {
74
75                switch (controller.what) {
76                case Controller::whatProlog:
77                        if (!prologWritten && stateNone == state) {
78                                s << "<?xml version=\"" << versionMajor << '.' << versionMinor << "\"?>\n";
79                                prologWritten = true;
80                        }
81                        break;  //      Controller::whatProlog
82
83                case Controller::whatTag:
84                        closeTagStart();
85                        s << '<';
86                        if (controller.str.empty()) {
87                                clearTagName();
88                                state = stateTagName;
89                        }
90                        else {
91                                s << controller.str;
92                                tags.push(controller.str);
93                                state = stateTag;
94                        }
95                        break;  //      Controller::whatTag
96
97                case Controller::whatTagEnd:
98                        endTag(controller.str);
99                        break;  //      Controller::whatTagEnd
100
101                case Controller::whatAttribute:
102                        switch (state) {
103                        case stateTagName:
104                                tags.push(tagName.str());
105                                break;
106
107                        case stateAttribute:
108                                s << '\"';
109                        }
110
111                        if (stateNone != state) {
112                                s << ' ' << controller.str << "=\"";
113                                state = stateAttribute;
114                        }
115                        // else throw some error - unexpected attribute (out of any tag)
116
117                        break;  //      Controller::whatAttribute
118
119                case Controller::whatCharData:
120                        closeTagStart();
121                        state = stateNone;
122                        break;  //      Controller::whatCharData
123                }
124
125                return  *this;
126        }
127
128private:
129        // state of the stream
130        typedef enum {stateNone, stateTag, stateAttribute, stateTagName}        state_type;
131
132        // tag name stack
133        typedef std::stack<std::string> tag_stack_type;
134
135        tag_stack_type  tags;
136        state_type      state;
137        std::ostream&   s;
138        bool    prologWritten;
139        std::ostringstream      tagName;
140
141        // I don't know any way easier (legal) to clear std::stringstream...
142        inline void clearTagName() {
143                const std::string       empty_str;
144                tagName.rdbuf()->str(empty_str);
145        }
146
147        // Close current tag
148        void closeTagStart(bool self_closed = false) {
149                if (stateTagName == state)
150                        tags.push(tagName.str());
151
152                // note: absence of 'break's is not an error
153                switch (state) {
154                case stateAttribute:
155                        s << '\"';
156
157                case stateTagName:
158                case stateTag:
159                        if (self_closed)
160                                s << '/';
161                        s << '>' << '\n';
162                }
163        }
164
165        // Close tag (may be with closing all of its children)
166        void endTag(const std::string& tag) {
167                bool    brk = false;
168
169                while (tags.size() > 0 && !brk) {
170                        if (stateNone == state)
171                                s << "</" << tags.top() << '>' << '\n';
172                        else {
173                                closeTagStart(true);
174                                state = stateNone;
175                        }
176                        brk = tag.empty() || tag == tags.top();
177                        tags.pop();
178                }
179        }
180};      //      class XmlStream
181
182// Helper functions, they may be simply overwritten
183// E.g. you may use std::string instead of const char*
184
185inline const XmlStream::Controller prolog() {
186        return XmlStream::Controller(XmlStream::Controller::whatProlog);
187}
188
189inline const XmlStream::Controller tag() {
190        return XmlStream::Controller(XmlStream::Controller::whatTag);
191}
192
193inline const XmlStream::Controller tag(const char* const tag_name) {
194        return XmlStream::Controller(XmlStream::Controller::whatTag, tag_name);
195}
196
197inline const XmlStream::Controller endtag() {
198        return XmlStream::Controller(XmlStream::Controller::whatTagEnd);
199}
200
201inline const XmlStream::Controller endtag(const char* const tag_name) {
202        return XmlStream::Controller(XmlStream::Controller::whatTagEnd, tag_name);
203}
204
205inline const XmlStream::Controller attr(const char* const attr_name) {
206        return XmlStream::Controller(XmlStream::Controller::whatAttribute, attr_name);
207}
208
209inline const XmlStream::Controller chardata() {
210        return XmlStream::Controller(XmlStream::Controller::whatCharData);
211}
212
213}       // namespace
214
215#endif  //  __XMLWRITER_H_2CC1D410_9DE8_4452_B8F0_F987EF152E06
Note: See TracBrowser for help on using the repository browser.