XmlSerializer.cpp

Go to the documentation of this file.
00001 /* Copyright (c) 2005,2007 Vivek Krishna
00002  *  Based on kxml2 by Stefan Haustein, Oberhausen, Rhld., Germany
00003  * Permission is hereby granted, free of charge, to any person obtaining a copy
00004  * of this software and associated documentation files (the "Software"), to deal
00005  * in the Software without restriction, including without limitation the rights
00006  * to use, copy, modify, merge, publish, distribute, sublicense, and/or
00007  * sell copies of the Software, and to permit persons to whom the Software is
00008  * furnished to do so, subject to the following conditions:
00009  *
00010  * The  above copyright notice and this permission notice shall be included in
00011  * all copies or substantial portions of the Software.
00012  *
00013  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00014  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00015  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00016  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00017  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00018  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
00019  * IN THE SOFTWARE. 
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   //   nspCounts[depth + 2] = nspCounts[depth];
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<<"&amp;";
00129       break;
00130     case '>' :
00131       writer<<"&gt;";
00132       break;
00133     case '<' :
00134       writer<<"&lt;";
00135       break;
00136     case '"' :
00137     case '\'' :
00138       if (c == quot) {
00139         writer<<(c == '"' ? "&quot;" : "&apos;");
00140         break;
00141       }
00142     default :
00143       //if(c < ' ')
00144       //        exception("Illegal control code:"+((int) c));
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   //return false;
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   // boil out if already defined
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   //        if (namespace == "")
00319   //            namespace = "";
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   //        int cnt = nspCounts[depth];
00373 
00374   if (nsp == "")
00375     nsp = "";
00376 
00377   //            depth--;
00378   //            pending = false;
00379   
00380   std::string prefix =(nsp=="")? "": getPrefix(nsp, false, true);
00381 
00382   //            pending = true;
00383   //            depth++;
00384 
00385   /*        if (cnt != nspCounts[depth]) {
00386             writer<<' ';
00387             writer<<"xmlns";
00388             if (nspStack[cnt * 2] != "") {
00389             writer<<':';
00390             writer<<nspStack[cnt * 2];
00391             }
00392             writer<<"=\"";
00393             writeEscaped(nspStack[cnt * 2 + 1], '"');
00394             writer<<'"';
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   //        if (nsp == "")
00426   //          nsp = "";
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by  doxygen 1.6.2