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