00001 // See ../../license.txt for license information. 00002 // 00003 // writeobj.cpp 00004 // 00005 // NOTES 00006 // A concrete subclass of object_writer which dumps an object. 00007 // 00008 // We write the objects like this: 00009 // 00010 /* 00011 object ::= 00012 object-start 00013 sub-object-list 00014 object-end 00015 00016 object-start ::= 00017 "<" TAGNAME ["(" attr-list ")"] ">" 00018 00019 object-end ::= 00020 "</" TAGNAME ">" 00021 00022 sub-object-list ::= 00023 (data-object | object)* 00024 00025 data-object ::= 00026 "<" TAGNAME ">" data "</" TAGNAME ">" 00027 00028 attr-list ::= 00029 [attr-pair ([", " attr-pair])*] 00030 00031 attr-pair ::= 00032 name "=" value 00033 */ 00034 // 21-Jul-2003 phamilton Created 00035 // 00036 00037 #define PERSIST_IN_LIBRARY_SOURCE 00038 #include "writeobj.hpp" 00039 00040 using namespace ph::persist::xml; 00041 00042 bool writeobj::start(const std::string &tagname) 00043 /* 00044 The input to start and end is "TAGNAME". The state table for the 00045 tree must start from TAGNAME and work out. 00046 */ 00047 { 00048 // write out the XML declaration at the top. 00049 if (_start) 00050 { 00051 *_stream << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" << std::endl << std::endl; 00052 _start = false; 00053 } 00054 00055 // Close off the previous tag (if there is one). 00056 if (!_tagname.empty()) 00057 { 00058 if (_data.empty()) 00059 { 00060 // object ::= 00061 // object-start 00062 // ... 00063 object_start(); 00064 _tabs++; 00065 } 00066 else 00067 data_object(); 00068 } 00069 00070 // and get started for the next tag. 00071 _attrs.clear(); 00072 _tagname = tagname; 00073 _data = ""; 00074 00075 return true; 00076 } 00077 00078 bool writeobj::end(const std::string &tagname) 00079 { 00080 // close off the current tag (if there is one). 00081 if (_tagname.empty()) 00082 { 00083 /* 00084 object ::= 00085 ... 00086 object-end 00087 */ 00088 // there was no accumulated tagname, just unnest, 00089 _tabs--; 00090 object_end(tagname); 00091 } 00092 else 00093 { 00094 if (_data.empty()) 00095 { 00096 /* 00097 object ::= 00098 object-start 00099 ... 00100 object-end 00101 */ 00102 // the last tag had no data, so the last one was an object. 00103 object_start(); 00104 object_end(tagname); 00105 } 00106 else 00107 data_object(); 00108 } 00109 00110 _attrs.clear(); 00111 _tagname = ""; 00112 _data = ""; 00113 00114 return true; 00115 } 00116 00117 bool writeobj::attr(const std::string &name, const std::string &value) 00118 { 00119 if (_tagname.empty()) 00120 { 00121 *_console << "bad state detected in attr(). _tagname should not be empty." << std::endl; 00122 return false; 00123 } 00124 if (!_data.empty()) 00125 { 00126 *_console << "bad state detected in attr(). _data should be empty." << std::endl; 00127 return false; 00128 } 00129 // and save this attribute. 00130 _attrs[name] = value; 00131 return true; 00132 } 00133 00134 bool writeobj::data(const std::string &d) 00135 { 00136 if (!_data.empty()) 00137 { 00138 *_console << "bad state detected in data(). _data should be empty." << std::endl; 00139 return false; 00140 } 00141 // and save this data. 00142 _data = d; 00143 return true; 00144 } 00145 00146 void writeobj::object_start() 00147 /* 00148 object-start ::= 00149 "<" TAGNAME ["(" attr-list ")"] ">" 00150 00151 attr-list ::= 00152 [attr-pair ([", " attr-pair])*] 00153 00154 attr-pair ::= 00155 name "=" "\"" value "\"" 00156 */ 00157 { 00158 if (_tagname.empty()) 00159 { 00160 *_console << "bad state detected in object_decl(). _tagname should not be empty." << std::endl; 00161 return; 00162 } 00163 tabs(); 00164 *_stream << "<" << _tagname; 00165 if (!_attrs.empty()) 00166 { 00167 *_stream << " "; 00168 // how about a std::for_each for this guy. What would be the best way? 00169 for (std::map<std::string, std::string>::iterator i=_attrs.begin(); i != _attrs.end(); i++) 00170 { 00171 if (i != _attrs.begin()) 00172 *_stream << ", "; 00173 *_stream << i->first << "=\"" << i->second << "\""; 00174 } 00175 } 00176 *_stream << ">"; 00177 cr(); 00178 } 00179 00180 void writeobj::object_end(const std::string &tagname) 00181 /* 00182 object-end ::= 00183 "</" TAGNAME ">" 00184 */ 00185 { 00186 tabs(); 00187 *_stream << "</" << tagname << ">"; 00188 cr(); 00189 } 00190 00191 void writeobj::data_object() 00192 /* 00193 data-object ::= 00194 "<" TAGNAME ">" data "</" TAGNAME ">" 00195 */ 00196 { 00197 tabs(); *_stream << "<" << _tagname << ">" << _data << "</" << _tagname << ">"; cr(); 00198 } 00199 00200 void writeobj::tabs() 00201 { 00202 for (int i=0; i<_tabs; i++) 00203 *_stream << " "; 00204 } 00205 00206 void writeobj::cr() 00207 { 00208 *_stream << std::endl; 00209 } 00210