00001 #ifndef XML_GENERATOR_IMPLEMENTATION_FILE
00002 #define XML_GENERATOR_IMPLEMENTATION_FILE
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "string_manipulation.h"
00019 #include "xml_generator.h"
00020
00021 #include <basis/istring.h>
00022 #include <basis/log_base.h>
00023 #include <data_struct/stack.cpp>
00024 #include <data_struct/string_table.h>
00025
00026 #undef LOG
00027 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger(), s);
00028
00030
00031 class tag_info
00032 {
00033 public:
00034 istring _tag_name;
00035 string_table _attribs;
00036
00037 tag_info() {}
00038
00039 tag_info(const istring &tag_name, const string_table &attribs)
00040 : _tag_name(tag_name), _attribs(attribs) {}
00041 };
00042
00044
00045 class tag_stack : public stack<tag_info>
00046 {
00047 public:
00048 tag_stack() : stack<tag_info>(0) {}
00049 };
00050
00052
00053 xml_generator::xml_generator(int mods)
00054 : _tags(new tag_stack),
00055 _accumulator(new istring),
00056 _human_read(mods & HUMAN_READABLE),
00057 _clean_chars(mods & CLEAN_ILLEGAL_CHARS),
00058 _indentation(2)
00059 {
00060 }
00061
00062 xml_generator::~xml_generator()
00063 {
00064 WHACK(_tags);
00065 WHACK(_accumulator);
00066 }
00067
00068 const char *xml_generator::outcome_name(const outcome &to_name)
00069 {
00070 switch (to_name.value()) {
00071 case ERRONEOUS_TAG: return "ERRONEOUS_TAG";
00072 default: return common::outcome_name(to_name);
00073 }
00074 }
00075
00076 void xml_generator::set_indentation(int to_indent)
00077 {
00078 if (to_indent <= 0) to_indent = 1;
00079 _indentation = to_indent;
00080 }
00081
00082 void xml_generator::reset()
00083 {
00084 _accumulator->reset();
00085
00086 while (_tags->pop() == common::OKAY) {}
00087 }
00088
00089 istring xml_generator::generate()
00090 {
00091 istring to_return;
00092 generate(to_return);
00093 return to_return;
00094 }
00095
00096 void xml_generator::generate(istring &generated)
00097 {
00098 close_all_tags();
00099 generated = "<?xml version=\"1.0\"?>";
00100 if (_human_read) generated += log_base::platform_ending();
00101 generated += *_accumulator;
00102 }
00103
00104 outcome xml_generator::open_tag(const istring &tag_name)
00105 {
00106 string_table junk;
00107 return open_tag(tag_name, junk);
00108 }
00109
00110 outcome xml_generator::add_header(const istring &tag_name,
00111 const string_table &attributes)
00112 {
00113 tag_info new_item(tag_name, attributes);
00114 print_open_tag(new_item, HEADER_TAG);
00115 return OKAY;
00116 }
00117
00118 outcome xml_generator::open_tag(const istring &tag_name, const string_table &attributes)
00119 {
00120 tag_info new_item(tag_name, attributes);
00121 print_open_tag(new_item);
00122 _tags->push(new_item);
00123 return OKAY;
00124 }
00125
00126 outcome xml_generator::close_tag(const istring &tag_name)
00127 {
00128 if (_tags->elements() < 1) return NOT_FOUND;
00129
00130 if (_tags->top()._tag_name != tag_name) return ERRONEOUS_TAG;
00131 print_close_tag(tag_name);
00132 _tags->pop();
00133 return OKAY;
00134 }
00135
00136 void xml_generator::close_all_tags()
00137 {
00138 while (_tags->elements()) {
00139 close_tag(_tags->top()._tag_name);
00140 }
00141 }
00142
00143 outcome xml_generator::add_content(const istring &content)
00144 {
00145 if (_human_read) {
00146 istring indentata = string_manipulation::indentation(_indentation);
00147 int num_indents = _tags->elements();
00148 for (int i = 0; i < num_indents; i++)
00149 *_accumulator += indentata;
00150 }
00151 if (_clean_chars)
00152 *_accumulator += clean_reserved(content);
00153 else
00154 *_accumulator += content;
00155 if (_human_read) *_accumulator += log_base::platform_ending();
00156 return OKAY;
00157 }
00158
00159 void xml_generator::print_open_tag(const tag_info &to_print, int type)
00160 {
00161 bool is_header = false;
00162 if (type == HEADER_TAG) is_header = true;
00163
00164 if (_human_read) {
00165
00166 istring indentata = string_manipulation::indentation(_indentation);
00167 int num_indents = _tags->elements();
00168 for (int i = 0; i < num_indents; i++)
00169 *_accumulator += indentata;
00170 }
00171
00172 if (is_header)
00173 *_accumulator += "<?";
00174 else
00175 *_accumulator += "<";
00176 if (_clean_chars)
00177 *_accumulator += clean_reserved(to_print._tag_name);
00178 else
00179 *_accumulator += to_print._tag_name;
00180 for (int i = 0; i < to_print._attribs.symbols(); i++) {
00181 istring name, content;
00182 to_print._attribs.retrieve(i, name, content);
00183 if (_clean_chars) {
00184
00185 clean_reserved_mod(name, true);
00186 clean_reserved_mod(content);
00187 }
00188 *_accumulator += " ";
00189 *_accumulator += name;
00190 *_accumulator += "=\"";
00191 *_accumulator += content;
00192 *_accumulator += "\"";
00193 }
00194 if (is_header)
00195 *_accumulator += "?>";
00196 else
00197 *_accumulator += ">";
00198 if (_human_read) *_accumulator += log_base::platform_ending();
00199 }
00200
00201 void xml_generator::print_close_tag(const istring &tag_name)
00202 {
00203 if (_human_read) {
00204 istring indentata = string_manipulation::indentation(_indentation);
00205 int num_indents = _tags->elements() - 1;
00206 for (int i = 0; i < num_indents; i++)
00207 *_accumulator += indentata;
00208 }
00209 *_accumulator += "</";
00210 if (_clean_chars)
00211 *_accumulator += clean_reserved(tag_name);
00212 else
00213 *_accumulator += tag_name;
00214 *_accumulator += ">";
00215 if (_human_read) *_accumulator += log_base::platform_ending();
00216 }
00217
00218 #define PLUGIN_REPLACEMENT(posn, repl_string) { \
00219 to_modify.zap(posn, posn); \
00220 to_modify.insert(posn, repl_string); \
00221 posn += int(strlen(repl_string)) - 1; \
00222 }
00223
00224
00225 void xml_generator::clean_reserved_mod(istring &to_modify,
00226 bool replace_spaces)
00227 {
00228
00229 const char *quot = """;
00230 const char *amp = "&";
00231 const char *lt = "<";
00232 const char *gt = ">";
00233 const char *apos = "'";
00234 const char *space = "_";
00235
00236
00237 for (int i = 0; i < to_modify.length(); i++) {
00238 switch (to_modify[i]) {
00239 case '"': PLUGIN_REPLACEMENT(i, quot); break;
00240 case '&': PLUGIN_REPLACEMENT(i, amp); break;
00241 case '<': PLUGIN_REPLACEMENT(i, lt); break;
00242 case '>': PLUGIN_REPLACEMENT(i, gt); break;
00243 case '\'': PLUGIN_REPLACEMENT(i, apos); break;
00244 case ' ': if (replace_spaces) PLUGIN_REPLACEMENT(i, space); break;
00245 default: continue;
00246 }
00247 }
00248 }
00249
00250 istring xml_generator::clean_reserved(const istring &to_modify,
00251 bool replace_spaces)
00252 {
00253 istring to_return = to_modify;
00254 clean_reserved_mod(to_return, replace_spaces);
00255 return to_return;
00256 }
00257
00258
00259 #endif //XML_GENERATOR_IMPLEMENTATION_FILE
00260