00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "precomp.h"
00030 #include "xml_writer.h"
00031 #include "xml_token_save.h"
00032 #include "string_help.h"
00033 #include "string_format.h"
00034 #include "xml_writer_generic.h"
00035
00036 static std::string insert_escapes_fast(std::string str);
00037
00039
00040
00041 CL_XMLWriter::CL_XMLWriter()
00042 {
00043 }
00044
00045 CL_XMLWriter::CL_XMLWriter(const CL_XMLWriter ©) : impl(copy.impl)
00046 {
00047 }
00048
00049 CL_XMLWriter::CL_XMLWriter(CL_IODevice *output, bool delete_output) : impl(new CL_XMLWriter_Generic)
00050 {
00051 impl->output = output;
00052 impl->delete_output = delete_output;
00053 }
00054
00055 CL_XMLWriter::~CL_XMLWriter()
00056 {
00057 }
00058
00060
00061
00062 bool CL_XMLWriter::get_insert_whitespace() const
00063 {
00064 return impl->insert_whitespace;
00065 }
00066
00067 void CL_XMLWriter::set_insert_whitespace(bool enable)
00068 {
00069 impl->insert_whitespace = enable;
00070 }
00071
00073
00074
00075 void CL_XMLWriter::write(const CL_XMLTokenSave &token)
00076 {
00077 if (!impl) return;
00078
00079 std::string str;
00080 switch (token.get_type())
00081 {
00082 case CL_XMLToken::NULL_TOKEN:
00083 return;
00084
00085 case CL_XMLToken::ELEMENT_TOKEN:
00086 if (token.get_variant() == CL_XMLToken::END)
00087 {
00088 str = cl_format("</%1>", insert_escapes_fast(token.get_name()));
00089 }
00090 else
00091 {
00092 str = cl_format("<%1", insert_escapes_fast(token.get_name()));
00093
00094 int size = token.get_attributes_number();
00095 for (int i=0; i<size; i++)
00096 {
00097 std::pair<std::string, std::string> attribute(token.get_attribute(i));
00098 str.append(cl_format(" %1=\"%2\"", insert_escapes_fast(attribute.first), insert_escapes_fast(attribute.second)));
00099 }
00100
00101 if (token.get_variant() == CL_XMLToken::SINGLE)
00102 str.append("/>");
00103 else
00104 str.append(">");
00105 }
00106 break;
00107
00108 case CL_XMLToken::TEXT_TOKEN:
00109 str = insert_escapes_fast(token.get_value());
00110 break;
00111
00112 case CL_XMLToken::CDATA_SECTION_TOKEN:
00113 str = cl_format("<!CDATA[%1]]>", token.get_value());
00114 break;
00115
00116 case CL_XMLToken::COMMENT_TOKEN:
00117 str = cl_format("<!--%1-->", token.get_value());
00118 break;
00119
00120 case CL_XMLToken::ENTITY_REFERENCE_TOKEN:
00121 case CL_XMLToken::ENTITY_TOKEN:
00122 case CL_XMLToken::PROCESSING_INSTRUCTION_TOKEN:
00123 case CL_XMLToken::DOCUMENT_TYPE_TOKEN:
00124 case CL_XMLToken::NOTATION_TOKEN:
00125 return;
00126 }
00127
00128 if (token.get_variant() == CL_XMLToken::END)
00129 {
00130 impl->indent--;
00131 }
00132
00133 if (impl->insert_whitespace)
00134 {
00135 std::string indent_tabs(impl->indent, '\t');
00136 impl->output->send(indent_tabs.data(), (int) indent_tabs.size());
00137 }
00138
00139 impl->output->send(str.data(), (int) str.size());
00140
00141 if (impl->insert_whitespace)
00142 {
00143 #ifdef WIN32
00144 impl->output->send("\r\n", 2);
00145 #else
00146 impl->output->send("\n", 2);
00147 #endif
00148 }
00149
00150 if (token.get_variant() == CL_XMLToken::BEGIN)
00151 {
00152 impl->indent++;
00153 }
00154 }
00155
00157
00158
00159 static std::string insert_escapes_fast(std::string str)
00160 {
00161 static std::string const amp("&");
00162 static std::string const quot(""");
00163 static std::string const apos("'");
00164 static std::string const lt("<");
00165 static std::string const gt(">");
00166
00167 std::string::size_type pos = 0;
00168 while (pos < str.size())
00169 {
00170 switch(str[pos])
00171 {
00172 case '&':
00173 str.replace(pos, 1, amp);
00174 pos += amp.size();
00175 break;
00176 case '\'':
00177 str.replace(pos, 1, apos);
00178 pos += apos.size();
00179 break;
00180 case '\"':
00181 str.replace(pos, 1, quot);
00182 pos += quot.size();
00183 break;
00184 case '<':
00185 str.replace(pos, 1, lt);
00186 pos += lt.size();
00187 break;
00188 case '>':
00189 str.replace(pos, 1, gt);
00190 pos += gt.size();
00191 break;
00192 default:
00193 ++pos;
00194 break;
00195 }
00196 }
00197 return str;
00198 }