XmlSerializer.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "xmlpull/XmlSerializer.h"
00025 #include "xmlpull/XmlPullParserException.h"
00026 #include "xmlpull/XmlUtils.h"
00027
00028 XmlSerializer::XmlSerializer(std::ostream &os,std::string enc)
00029 :writer(os),
00030 encoding(enc),
00031 elementStack(16),
00032 nspStack(16),
00033 nspCounts(8),
00034 indent(8)
00035 {
00036 init();
00037 }
00038
00039 XmlSerializer::XmlSerializer(std::string enc)
00040 :writer(std::cout),
00041 encoding(enc),
00042 elementStack(16),
00043 nspStack(16),
00044 nspCounts(8),
00045 indent(8)
00046 {
00047 init();
00048 }
00049
00050 XmlSerializer::~XmlSerializer()
00051 {
00052 }
00053
00054 void
00055 XmlSerializer::init()
00056 {
00057 nspCounts[0] = 2;
00058 nspCounts[1] = 2;
00059 nspStack[0] = "";
00060 nspStack[1] = "";
00061 nspStack[2] = "xml";
00062 nspStack[3] = "http://www.w3.org/XML/1998/namespace";
00063 pending = false;
00064 auto_ = 0;
00065 depth = 0;
00066 if (encoding.find("utf",0)!=std::string::npos)
00067 unicode = true;
00068 else
00069 unicode = false;
00070 }
00071
00072 void
00073 XmlSerializer::check(bool close)
00074 {
00075 if (!pending)
00076 return;
00077 depth++;
00078 pending = false;
00079
00080 if (indent.size() <= depth) {
00081 indent.resize(depth + 4);
00082 }
00083 indent[depth] = indent[depth - 1];
00084
00085 for (int i = nspCounts[depth - 1];
00086 i < nspCounts[depth];
00087 i++) {
00088
00089 writer<<' ';
00090 writer<<"xmlns";
00091 if (""!=nspStack[i * 2]) {
00092 writer<<':';
00093 writer<<nspStack[i * 2];
00094 }
00095 else if (getNamespace() != "" && nspStack[i * 2 + 1]!="")
00096 exception("Cannot set default namespace for elements in no namespace");
00097 writer<<"=\"";
00098 writeEscaped(nspStack[i * 2 + 1], '"');
00099 writer<<'"';
00100 }
00101
00102 if (nspCounts.size() <= depth + 1) {
00103 nspCounts.resize(depth + 8);
00104 }
00105
00106 nspCounts[depth + 1] = nspCounts[depth];
00107
00108
00109 writer<<(close ? " />" : ">");
00110 }
00111
00112 void
00113 XmlSerializer::writeEscaped(std::string s, int quot)
00114 {
00115
00116 for (size_t i = 0; i < s.length(); i++) {
00117 unsigned char c = s[i];
00118 switch (c) {
00119 case '\n':
00120 case '\r':
00121 case '\t':
00122 if(quot == -1)
00123 writer<<c;
00124 else
00125 writer<<"&#"+((int) c)+';';
00126 break;
00127 case '&' :
00128 writer<<"&";
00129 break;
00130 case '>' :
00131 writer<<">";
00132 break;
00133 case '<' :
00134 writer<<"<";
00135 break;
00136 case '"' :
00137 case '\'' :
00138 if (c == quot) {
00139 writer<<(c == '"' ? """ : "'");
00140 break;
00141 }
00142 default :
00143
00144
00145
00146 if (c >= ' ' && c !='@' && (c < 127 || unicode))
00147 writer<<c;
00148 else
00149 writer<<"&#" << ((int) c) << ";";
00150 }
00151 }
00152 }
00153
00154
00155 void
00156 XmlSerializer::docdecl(std::string dd)
00157 {
00158 writer<<"<!DOCTYPE";
00159 writer<<dd;
00160 writer<<">";
00161 }
00162
00163 void
00164 XmlSerializer::endDocument() {
00165 while (depth > 0) {
00166 endTag(
00167 elementStack[depth * 3 - 3],
00168 elementStack[depth * 3 - 1]);
00169 }
00170 flush();
00171 }
00172
00173 void
00174 XmlSerializer::entityRef(std::string name)
00175 {
00176 check(false);
00177 writer<<'&';
00178 writer<<name;
00179 writer<<';';
00180 }
00181
00182 bool
00183 XmlSerializer:: getFeature(std::string name) {
00184
00185 return ("http://xmlpull.org/v1/doc/features.html#indent-output" == name)
00186 ? indent[depth]
00187 : false;
00188 }
00189
00190 std::string
00191 XmlSerializer::getPrefix(std::string ns, bool create)
00192 {
00193 return getPrefix(ns, false, create);
00194 }
00195
00196
00197 std::string
00198 XmlSerializer::getPrefix(std::string ns,
00199 bool includeDefault,
00200 bool create)
00201 {
00202
00203 for (int i = nspCounts[depth + 1] * 2 - 2;
00204 i >= 0;
00205 i -= 2) {
00206
00207 if (nspStack[i + 1] == ns
00208 && (includeDefault || nspStack[i]!="")) {
00209 std::string cand = nspStack[i];
00210 for (int j = i + 2;
00211 j < nspCounts[depth + 1] * 2;
00212 j++) {
00213 if (nspStack[j]==cand) {
00214 cand = "";
00215 break;
00216 }
00217 }
00218 if (cand != "")
00219 return cand;
00220 }
00221 }
00222
00223 if (!create)
00224 return "";
00225
00226 std::string prefix;
00227
00228 if (ns=="")
00229 prefix = "";
00230 else {
00231 do {
00232 prefix = "n" + (auto_++);
00233 for (int i = nspCounts[depth + 1] * 2 - 2;
00234 i >= 0;
00235 i -= 2) {
00236 if (prefix==nspStack[i]) {
00237 prefix = "";
00238 break;
00239 }
00240 }
00241 }
00242 while (prefix == "");
00243 }
00244
00245 bool p = pending;
00246 pending = false;
00247 setPrefix(prefix, ns);
00248 pending = p;
00249 return prefix;
00250 }
00251
00252 void
00253 XmlSerializer::ignorableWhitespace(std::string s)
00254 {
00255 text(s);
00256 }
00257
00258 void
00259 XmlSerializer::setFeature(std::string name, bool value)
00260 {
00261 if ("http://xmlpull.org/v1/doc/features.html#indent-output"==name) {
00262 indent[depth] = value;
00263 }
00264 else
00265 exception("Unsupported Feature");
00266 }
00267
00268 void
00269 XmlSerializer::setPrefix(std::string prefix, std::string nsp)
00270 {
00271 check(false);
00272 std::string defined = getPrefix(nsp, true, false);
00273
00274
00275
00276 if (prefix==defined)
00277 return;
00278
00279 int pos = (nspCounts[depth + 1]++) << 1;
00280
00281 if (nspStack.size() < pos + 1) {
00282 nspStack.resize(nspStack.size() + 16);
00283 }
00284
00285 nspStack[pos++] = prefix;
00286 nspStack[pos] = nsp;
00287 }
00288
00289 void
00290 XmlSerializer::startDocument(std::string enc,
00291 bool standalone)
00292 {
00293 writer<<"<?xml version='1.0' ";
00294
00295 if (encoding != "") {
00296 this->encoding = enc;
00297 if (encoding.find("utf",0)!=std::string::npos)
00298 unicode = true;
00299 }
00300
00301 if (encoding != "") {
00302 writer<<"encoding='";
00303 writer<<encoding;
00304 writer<<"' ";
00305 }
00306
00307 writer<<"standalone='";
00308 writer<<(standalone ? "yes" : "no");
00309 writer<<"' ";
00310 writer<<"?>";
00311 }
00312
00313 XmlSerializer&
00314 XmlSerializer::startTag(std::string nsp, std::string name)
00315 {
00316 check(false);
00317
00318
00319
00320
00321 if (indent[depth]) {
00322 writer<<"\r\n";
00323 for (int i = 0; i < depth; i++)
00324 writer<<" ";
00325 }
00326
00327 int esp = depth * 3;
00328 if (elementStack.size() < esp + 3) {
00329 elementStack.resize(elementStack.size() + 16);
00330 }
00331
00332 std::string prefix =
00333 nsp == ""
00334 ? ""
00335 : getPrefix(nsp, true, true);
00336
00337 if (nsp=="") {
00338 for (int i = nspCounts[depth];
00339 i < nspCounts[depth + 1];
00340 i++) {
00341
00342 if (nspStack[i * 2]== "" && nspStack[i * 2 + 1]!= "") {
00343 exception("Cannot set default namespace for elements in no namespace");
00344 }
00345 }
00346 }
00347
00348 elementStack[esp++] = nsp;
00349 elementStack[esp++] = prefix;
00350 elementStack[esp] = name;
00351
00352 writer<<'<';
00353 if (prefix!="") {
00354 writer<<prefix;
00355 writer<<':';
00356 }
00357
00358 writer<<name;
00359
00360 pending = true;
00361 return *this;
00362 }
00363
00364 XmlSerializer&
00365 XmlSerializer::attribute(std::string nsp,
00366 std::string name,
00367 std::string value)
00368 {
00369 if (!pending)
00370 exception("illegal position for attribute");
00371
00372
00373
00374 if (nsp == "")
00375 nsp = "";
00376
00377
00378
00379
00380 std::string prefix =(nsp=="")? "": getPrefix(nsp, false, true);
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398 writer<<' ';
00399 if (prefix!="") {
00400 writer<<prefix;
00401 writer<<':';
00402 }
00403 writer<<name;
00404 writer<<'=';
00405 char q = value.find('"') == std::string::npos ? '"' : '\'';
00406 writer<<q;
00407 writeEscaped(value, q);
00408 writer<<q;
00409 return *this;
00410 }
00411
00412 void
00413 XmlSerializer::flush()
00414 {
00415 check(false);
00416 writer.flush();
00417 }
00418
00419 XmlSerializer&
00420 XmlSerializer::endTag(std::string nsp, std::string name)
00421 {
00422
00423 if (!pending)
00424 depth--;
00425
00426
00427
00428 if ((nsp == ""
00429 && elementStack[depth * 3] != "")
00430 || (nsp != ""
00431 && nsp!=elementStack[depth * 3])
00432 || elementStack[depth * 3 + 2] != name)
00433
00434 exception("</{"+nsp+"}"+name+"> does not match start");
00435
00436 if (pending) {
00437 check(true);
00438 depth--;
00439 }
00440 else {
00441 if (indent[depth + 1]) {
00442 writer<<"\r\n";
00443 for (int i = 0; i < depth; i++)
00444 writer<<" ";
00445 }
00446
00447 writer<<"</";
00448 std::string prefix = elementStack[depth * 3 + 1];
00449 if (prefix != "") {
00450 writer<<prefix;
00451 writer<<':';
00452 }
00453 writer<<name;
00454 writer<<'>';
00455 }
00456
00457 nspCounts[depth + 1] = nspCounts[depth];
00458 return *this;
00459 }
00460
00461
00462 std::string
00463 XmlSerializer::getNamespace()
00464 {
00465 return getDepth() == 0 ? "" : elementStack[getDepth() * 3 - 3];
00466 }
00467
00468 std::string
00469 XmlSerializer::getName()
00470 {
00471 return getDepth() == 0 ? "" : elementStack[getDepth() * 3 - 1];
00472 }
00473
00474 int
00475 XmlSerializer::getDepth() {
00476 return pending ? depth + 1 : depth;
00477 }
00478
00479 XmlSerializer&
00480 XmlSerializer::text(std::string txt){
00481 check(false);
00482 indent[depth] = false;
00483 writeEscaped(txt, -1);
00484 return *this;
00485 }
00486
00487 XmlSerializer&
00488 XmlSerializer::text(std::string txt, int start, int len)
00489 {
00490 text(txt.substr(start, len));
00491 return *this;
00492 }
00493
00494 void
00495 XmlSerializer::cdsect(std::string data)
00496 {
00497 check(false);
00498 writer<<"<![CDATA[";
00499 writer<<data;
00500 writer<<"]]>";
00501 }
00502
00503 void
00504 XmlSerializer::comment(std::string comment) {
00505 check(false);
00506 writer<<"<!--";
00507 writer<<comment;
00508 writer<<"-->";
00509 }
00510
00511 void
00512 XmlSerializer::processingInstruction(std::string pi)
00513 {
00514 check(false);
00515 writer<<"<?";
00516 writer<<pi;
00517 writer<<"?>";
00518 }
00519
00520 void
00521 XmlSerializer::exception (std::string desc)
00522 {
00523 XmlPullParserException e (desc,elementStack.front(),0,0);
00524 throw e;
00525 }