wsdlpull  1.23
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
XmlSerializer.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2005,2007 Vivek Krishna
2  * Based on kxml2 by Stefan Haustein, Oberhausen, Rhld., Germany
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to deal
5  * in the Software without restriction, including without limitation the rights
6  * to use, copy, modify, merge, publish, distribute, sublicense, and/or
7  * sell copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19  * IN THE SOFTWARE.
20  *
21  */
22 
23 
24 #include "xmlpull/XmlSerializer.h"
26 #include "xmlpull/XmlUtils.h"
27 
28 XmlSerializer::XmlSerializer(std::ostream &os,std::string enc)
29  :writer(os),
30  encoding(enc),
31  elementStack(16),
32  nspStack(16),
33  nspCounts(8),
34  indent(8)
35 {
36  init();
37 }
38 
40  :writer(std::cout),
41  encoding(enc),
42  elementStack(16),
43  nspStack(16),
44  nspCounts(8),
45  indent(8)
46 {
47  init();
48 }
49 
51 {
52 }
53 
54 void
55 XmlSerializer::init()
56 {
57  nspCounts[0] = 2;
58  nspCounts[1] = 2;
59  nspStack[0] = "";
60  nspStack[1] = "";
61  nspStack[2] = "xml";
62  nspStack[3] = "http://www.w3.org/XML/1998/namespace";
63  pending = false;
64  auto_ = 0;
65  depth = 0;
66  if (encoding.find("utf",0)!=std::string::npos)
67  unicode = true;
68  else
69  unicode = false;
70 }
71 
72 void
73 XmlSerializer::check(bool close)
74 {
75  if (!pending)
76  return;
77  depth++;
78  pending = false;
79 
80  if (indent.size() <= depth) {
81  indent.resize(depth + 4);
82  }
83  indent[depth] = indent[depth - 1];
84 
85  for (int i = nspCounts[depth - 1];
86  i < nspCounts[depth];
87  i++) {
88 
89  writer<<' ';
90  writer<<"xmlns";
91  if (""!=nspStack[i * 2]) {
92  writer<<':';
93  writer<<nspStack[i * 2];
94  }
95  else if (getNamespace() != "" && nspStack[i * 2 + 1]!="")
96  exception("Cannot set default namespace for elements in no namespace");
97  writer<<"=\"";
98  writeEscaped(nspStack[i * 2 + 1], '"');
99  writer<<'"';
100  }
101 
102  if (nspCounts.size() <= depth + 1) {
103  nspCounts.resize(depth + 8);
104  }
105 
106  nspCounts[depth + 1] = nspCounts[depth];
107  // nspCounts[depth + 2] = nspCounts[depth];
108 
109  writer<<(close ? " />" : ">");
110 }
111 
112 void
113 XmlSerializer::writeEscaped(std::string s, int quot)
114 {
115 
116  for (size_t i = 0; i < s.length(); i++) {
117  unsigned char c = s[i];
118  switch (c) {
119  case '\n':
120  case '\r':
121  case '\t':
122  if(quot == -1)
123  writer<<c;
124  else
125  writer<<"&#"+((int) c)+';';
126  break;
127  case '&' :
128  writer<<"&amp;";
129  break;
130  case '>' :
131  writer<<"&gt;";
132  break;
133  case '<' :
134  writer<<"&lt;";
135  break;
136  case '"' :
137  case '\'' :
138  if (c == quot) {
139  writer<<(c == '"' ? "&quot;" : "&apos;");
140  break;
141  }
142  default :
143  //if(c < ' ')
144  // exception("Illegal control code:"+((int) c));
145 
146  if (c >= ' ' && c !='@' && (c < 127 || unicode))
147  writer<<c;
148  else
149  writer<<"&#" << ((int) c) << ";";
150  }
151  }
152 }
153 
154 
155 void
156 XmlSerializer::docdecl(std::string dd)
157 {
158  writer<<"<!DOCTYPE";
159  writer<<dd;
160  writer<<">";
161 }
162 
163 void
165  while (depth > 0) {
166  endTag(
167  elementStack[depth * 3 - 3],
168  elementStack[depth * 3 - 1]);
169  }
170  flush();
171 }
172 
173 void
174 XmlSerializer::entityRef(std::string name)
175 {
176  check(false);
177  writer<<'&';
178  writer<<name;
179  writer<<';';
180 }
181 
182 bool
183 XmlSerializer:: getFeature(std::string name) {
184  //return false;
185  return ("http://xmlpull.org/v1/doc/features.html#indent-output" == name)
186  ? indent[depth]
187  : false;
188 }
189 
190 std::string
191 XmlSerializer::getPrefix(std::string ns, bool create)
192 {
193  return getPrefix(ns, false, create);
194 }
195 
196 
197 std::string
199  bool includeDefault,
200  bool create)
201 {
202 
203  for (int i = nspCounts[depth + 1] * 2 - 2;
204  i >= 0;
205  i -= 2) {
206 
207  if (nspStack[i + 1] == ns
208  && (includeDefault || nspStack[i]!="")) {
209  std::string cand = nspStack[i];
210  for (int j = i + 2;
211  j < nspCounts[depth + 1] * 2;
212  j++) {
213  if (nspStack[j]==cand) {
214  cand = "";
215  break;
216  }
217  }
218  if (cand != "")
219  return cand;
220  }
221  }
222 
223  if (!create)
224  return "";
225 
226  std::string prefix;
227 
228  if (ns=="")
229  prefix = "";
230  else {
231  do {
232  prefix = "n" + (auto_++);
233  for (int i = nspCounts[depth + 1] * 2 - 2;
234  i >= 0;
235  i -= 2) {
236  if (prefix==nspStack[i]) {
237  prefix = "";
238  break;
239  }
240  }
241  }
242  while (prefix == "");
243  }
244 
245  bool p = pending;
246  pending = false;
247  setPrefix(prefix, ns);
248  pending = p;
249  return prefix;
250 }
251 
252 void
254 {
255  text(s);
256 }
257 
258 void
259 XmlSerializer::setFeature(std::string name, bool value)
260 {
261  if ("http://xmlpull.org/v1/doc/features.html#indent-output"==name) {
262  indent[depth] = value;
263  }
264  else
265  exception("Unsupported Feature");
266 }
267 
268 void
269 XmlSerializer::setPrefix(std::string prefix, std::string nsp)
270 {
271  check(false);
272  std::string defined = getPrefix(nsp, true, false);
273 
274  // boil out if already defined
275 
276  if (prefix==defined)
277  return;
278 
279  int pos = (nspCounts[depth + 1]++) << 1;
280 
281  if (nspStack.size() < pos + 1) {
282  nspStack.resize(nspStack.size() + 16);
283  }
284 
285  nspStack[pos++] = prefix;
286  nspStack[pos] = nsp;
287 }
288 
289 void
291  bool standalone)
292  {
293  writer<<"<?xml version='1.0' ";
294 
295  if (encoding != "") {
296  this->encoding = enc;
297  if (encoding.find("utf",0)!=std::string::npos)
298  unicode = true;
299  }
300 
301  if (encoding != "") {
302  writer<<"encoding='";
303  writer<<encoding;
304  writer<<"' ";
305  }
306 
307  writer<<"standalone='";
308  writer<<(standalone ? "yes" : "no");
309  writer<<"' ";
310  writer<<"?>";
311  }
312 
314 XmlSerializer::startTag(std::string nsp, std::string name)
315 {
316  check(false);
317 
318  // if (namespace == "")
319  // namespace = "";
320 
321  if (indent[depth]) {
322  writer<<"\r\n";
323  for (int i = 0; i < depth; i++)
324  writer<<" ";
325  }
326 
327  int esp = depth * 3;
328  if (elementStack.size() < esp + 3) {
329  elementStack.resize(elementStack.size() + 16);
330  }
331 
332  std::string prefix =
333  nsp == ""
334  ? ""
335  : getPrefix(nsp, true, true);
336 
337  if (nsp=="") {
338  for (int i = nspCounts[depth];
339  i < nspCounts[depth + 1];
340  i++) {
341 
342  if (nspStack[i * 2]== "" && nspStack[i * 2 + 1]!= "") {
343  exception("Cannot set default namespace for elements in no namespace");
344  }
345  }
346  }
347 
348  elementStack[esp++] = nsp;
349  elementStack[esp++] = prefix;
350  elementStack[esp] = name;
351 
352  writer<<'<';
353  if (prefix!="") {
354  writer<<prefix;
355  writer<<':';
356  }
357 
358  writer<<name;
359 
360  pending = true;
361  return *this;
362 }
363 
365 XmlSerializer::attribute(std::string nsp,
366  std::string name,
367  std::string value)
368 {
369  if (!pending)
370  exception("illegal position for attribute");
371 
372  // int cnt = nspCounts[depth];
373 
374  if (nsp == "")
375  nsp = "";
376 
377  // depth--;
378  // pending = false;
379 
380  std::string prefix =(nsp=="")? "": getPrefix(nsp, false, true);
381 
382  // pending = true;
383  // depth++;
384 
385  /* if (cnt != nspCounts[depth]) {
386  writer<<' ';
387  writer<<"xmlns";
388  if (nspStack[cnt * 2] != "") {
389  writer<<':';
390  writer<<nspStack[cnt * 2];
391  }
392  writer<<"=\"";
393  writeEscaped(nspStack[cnt * 2 + 1], '"');
394  writer<<'"';
395  }
396  */
397 
398  writer<<' ';
399  if (prefix!="") {
400  writer<<prefix;
401  writer<<':';
402  }
403  writer<<name;
404  writer<<'=';
405  char q = value.find('"') == std::string::npos ? '"' : '\'';
406  writer<<q;
407  writeEscaped(value, q);
408  writer<<q;
409  return *this;
410 }
411 
412 void
414 {
415  check(false);
416  writer.flush();
417 }
418 
420 XmlSerializer::endTag(std::string nsp, std::string name)
421 {
422 
423  if (!pending)
424  depth--;
425  // if (nsp == "")
426  // nsp = "";
427 
428  if ((nsp == ""
429  && elementStack[depth * 3] != "")
430  || (nsp != ""
431  && nsp!=elementStack[depth * 3])
432  || elementStack[depth * 3 + 2] != name)
433 
434  exception("</{"+nsp+"}"+name+"> does not match start");
435 
436  if (pending) {
437  check(true);
438  depth--;
439  }
440  else {
441  if (indent[depth + 1]) {
442  writer<<"\r\n";
443  for (int i = 0; i < depth; i++)
444  writer<<" ";
445  }
446 
447  writer<<"</";
448  std::string prefix = elementStack[depth * 3 + 1];
449  if (prefix != "") {
450  writer<<prefix;
451  writer<<':';
452  }
453  writer<<name;
454  writer<<'>';
455  }
456 
457  nspCounts[depth + 1] = nspCounts[depth];
458  return *this;
459 }
460 
461 
462 std::string
463 XmlSerializer::getNamespace()
464 {
465  return getDepth() == 0 ? "" : elementStack[getDepth() * 3 - 3];
466 }
467 
468 std::string
469 XmlSerializer::getName()
470 {
471  return getDepth() == 0 ? "" : elementStack[getDepth() * 3 - 1];
472 }
473 
474 int
475 XmlSerializer::getDepth() {
476  return pending ? depth + 1 : depth;
477 }
478 
479 XmlSerializer&
480 XmlSerializer::text(std::string txt){
481  check(false);
482  indent[depth] = false;
483  writeEscaped(txt, -1);
484  return *this;
485  }
486 
487 XmlSerializer&
488 XmlSerializer::text(std::string txt, int start, int len)
489 {
490  text(txt.substr(start, len));
491  return *this;
492 }
493 
494 void
495 XmlSerializer::cdsect(std::string data)
496 {
497  check(false);
498  writer<<"<![CDATA[";
499  writer<<data;
500  writer<<"]]>";
501 }
502 
503 void
504 XmlSerializer::comment(std::string comment) {
505  check(false);
506  writer<<"<!--";
507  writer<<comment;
508  writer<<"-->";
509 }
510 
511 void
512 XmlSerializer::processingInstruction(std::string pi)
513 {
514  check(false);
515  writer<<"<?";
516  writer<<pi;
517  writer<<"?>";
518 }
519 
520 void
521 XmlSerializer::exception (std::string desc)
522 {
523  XmlPullParserException e (desc,elementStack.front(),0,0);
524  throw e;
525 }
void ignorableWhitespace(std::string s)
XmlSerializer & attribute(std::string nsp, std::string name, std::string value)
void startDocument(std::string encoding, bool standalone)
XmlSerializer & endTag(std::string nsp, std::string name)
std::string getPrefix(std::string nsp, bool create)
XmlSerializer & text(std::string txt)
bool getFeature(std::string name)
XmlSerializer & startTag(std::string nsp, std::string name)
XmlSerializer(std::ostream &os, std::string encoding="utf")
void docdecl(std::string dd)
void entityRef(std::string name)
void setPrefix(std::string prefix, std::string nsp)
void setFeature(std::string name, bool value)
std::string getNamespace()