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
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #ifndef XS_NO_COMMENT
00041 #define XS_NO_COMMENT // no #pragma comment(lib, ...) statements in .lib files to enable static linking
00042 #endif
00043
00044 #include "xmlstorage.h"
00045
00046
00047 namespace XMLStorage {
00048
00049
00050
00051 #ifdef __GNUC__
00052 const LPCXSSTR XS_EMPTY = XS_EMPTY_STR;
00053 const LPCXSSTR XS_TRUE = XS_TRUE_STR;
00054 const LPCXSSTR XS_FALSE = XS_FALSE_STR;
00055 const LPCXSSTR XS_INTFMT = XS_INTFMT_STR;
00056 const LPCXSSTR XS_FLOATFMT = XS_FLOATFMT_STR;
00057 #endif
00058
00059 const XS_String XS_KEY = XS_KEY_STR;
00060 const XS_String XS_VALUE = XS_VALUE_STR;
00061 const XS_String XS_PROPERTY = XS_PROPERTY_STR;
00062
00063
00064
00065 static std::string unescape(const char* s, char b, char e)
00066 {
00067 const char* end = s + strlen(s);
00068
00069
00070
00071
00072
00073
00074
00075 if (*s == b)
00076 if (end>s && end[-1]==e)
00077 ++s, --end;
00078
00079 return std::string(s, end-s);
00080 }
00081
00082 inline std::string unescape(const char* s)
00083 {
00084 return unescape(s, '"', '"');
00085 }
00086
00087
00088 static std::string unescape(const char* s, size_t l, char b, char e)
00089 {
00090 const char* end = s + l;
00091
00092
00093
00094
00095
00096
00097
00098 if (*s == b)
00099 if (end>s && end[-1]==e)
00100 ++s, --end;
00101
00102 return std::string(s, end-s);
00103 }
00104
00105 inline std::string unescape(const char* s, size_t l)
00106 {
00107 return unescape(s, l, '"', '"');
00108 }
00109
00110
00111
00112 bool XMLPos::go(const XPath& xpath)
00113 {
00114 XMLNode* node = xpath._absolute? _root: _cur;
00115
00116 node = node->find_relative(xpath);
00117
00118 if (node) {
00119 go_to(node);
00120 return true;
00121 } else
00122 return false;
00123 }
00124
00125
00126 bool const_XMLPos::go(const XPath& xpath)
00127 {
00128 const XMLNode* node = xpath._absolute? _root: _cur;
00129
00130 node = node->find_relative(xpath);
00131
00132 if (node) {
00133 go_to(node);
00134 return true;
00135 } else
00136 return false;
00137 }
00138
00139
00140 const char* XPathElement::parse(const char* path)
00141 {
00142 const char* slash = strchr(path, '/');
00143 if (slash == path)
00144 return NULL;
00145
00146 size_t l = slash? slash-path: strlen(path);
00147 std::string comp(path, l);
00148 path += l;
00149
00150
00151 const char* bracket = strchr(comp.c_str(), '[');
00152 l = bracket? bracket-comp.c_str(): comp.length();
00153 _child_name.assign(comp.c_str(), l);
00154
00155 int n = 0;
00156 if (bracket) {
00157 std::string expr = unescape(bracket, '[', ']');
00158 const char* p = expr.c_str();
00159
00160 n = atoi(p);
00161
00162 if (n)
00163 _child_idx = n - 1;
00164
00165 const char* at = strchr(p, '@');
00166
00167 if (at) {
00168 p = at + 1;
00169 const char* equal = strchr(p, '=');
00170
00171
00172 if (equal) {
00173 _attr_name = unescape(p, equal-p);
00174 _attr_value = unescape(equal+1);
00175 }
00176 }
00177 }
00178
00179 return path;
00180 }
00181
00182 XMLNode* XPathElement::find(XMLNode* node) const
00183 {
00184 int n = 0;
00185
00186 for(XMLNode::Children::const_iterator it=node->_children.begin(); it!=node->_children.end(); ++it)
00187 if (matches(**it, n))
00188 return *it;
00189
00190 return NULL;
00191 }
00192
00193 const XMLNode* XPathElement::const_find(const XMLNode* node) const
00194 {
00195 int n = 0;
00196
00197 for(XMLNode::Children::const_iterator it=node->_children.begin(); it!=node->_children.end(); ++it)
00198 if (matches(**it, n))
00199 return *it;
00200
00201 return NULL;
00202 }
00203
00204 bool XPathElement::matches(const XMLNode& node, int& n) const
00205 {
00206 if (node != _child_name)
00207 if (_child_name != XS_TEXT("*"))
00208 return false;
00209
00210 if (!_attr_name.empty())
00211 if (node.get(_attr_name) != _attr_value)
00212 return false;
00213
00214 if (_child_idx == -1)
00215 return true;
00216 else if (n++ == _child_idx)
00217 return true;
00218 else
00219 return false;
00220 }
00221
00222
00223 void XPath::init(const char* path)
00224 {
00225
00226 if (*path == '/') {
00227 _absolute = true;
00228 ++path;
00229 } else
00230 _absolute = false;
00231
00232
00233 while(*path) {
00234 XPathElement elem;
00235
00236 path = elem.parse(path);
00237
00238 if (!path)
00239 break;
00240
00241 if (*path == '/')
00242 ++path;
00243
00244 push_back(elem);
00245 }
00246 }
00247
00248
00249 const XMLNode* XMLNode::find_relative(const XPath& xpath) const
00250 {
00251 const XMLNode* node = this;
00252
00253 for(XPath::const_iterator it=xpath.begin(); it!=xpath.end(); ++it) {
00254 node = it->const_find(node);
00255
00256 if (!node)
00257 return NULL;
00258 }
00259
00260 return node;
00261 }
00262
00263 XMLNode* XMLNode::find_relative(const XPath& xpath)
00264 {
00265 XMLNode* node = this;
00266
00267 for(XPath::const_iterator it=xpath.begin(); it!=xpath.end(); ++it) {
00268 node = it->find(node);
00269
00270 if (!node)
00271 return NULL;
00272 }
00273
00274 return node;
00275 }
00276
00277 XMLNode* XMLNode::create_relative(const XPath& xpath)
00278 {
00279 XMLNode* node = this;
00280
00281 for(XPath::const_iterator it=xpath.begin(); it!=xpath.end(); ++it) {
00282 XMLNode* child = it->find(node);
00283
00284 if (!child) {
00285 child = new XMLNode(it->_child_name);
00286 node->add_child(child);
00287
00288 if (!it->_attr_name.empty())
00289 (*this)[it->_attr_name] = it->_attr_value;
00290 }
00291
00292 node = child;
00293 }
00294
00295 return node;
00296 }
00297
00298
00299 int XMLNode::count(XPath::const_iterator from, const XPath::const_iterator& to) const
00300 {
00301 const XPathElement& elem = *from++;
00302 int cnt = 0;
00303 int n = 0;
00304
00305 for(XMLNode::Children::const_iterator it=_children.begin(); it!=_children.end(); ++it)
00306 if (elem.matches(**it, n)) {
00307 if (from != to)
00308
00309 cnt += (*it)->count(from, to);
00310 else
00311
00312 ++cnt;
00313 }
00314
00315 return cnt;
00316 }
00317
00318
00319 bool XMLNode::filter(const XPath& xpath, XMLNode& target) const
00320 {
00321 XMLNode* ret = filter(xpath.begin(), xpath.end());
00322
00323 if (ret) {
00324
00325 target._children.move(ret->_children);
00326 target._attributes = ret->_attributes;
00327
00328 delete ret;
00329
00330 return true;
00331 } else
00332 return false;
00333 }
00334
00335
00336 XMLNode* XMLNode::filter(XPath::const_iterator from, const XPath::const_iterator& to) const
00337 {
00338 XMLNode* copy = NULL;
00339
00340 const XPathElement& elem = *from++;
00341 int cnt = 0;
00342 int n = 0;
00343
00344 for(XMLNode::Children::const_iterator it=_children.begin(); it!=_children.end(); ++it)
00345 if (elem.matches(**it, n)) {
00346 if (!copy)
00347 copy = new XMLNode(*this, XMLNode::COPY_NOCHILDREN);
00348
00349 if (from != to) {
00350 XMLNode* ret = (*it)->filter(from, to);
00351
00352 if (ret) {
00353 copy->add_child(ret);
00354 ++cnt;
00355 }
00356 } else {
00357 copy->add_child(new XMLNode(**it, XMLNode::COPY_NOCHILDREN));
00358 ++cnt;
00359 }
00360 }
00361
00362 if (cnt > 0) {
00363 return copy;
00364 } else {
00365 delete copy;
00366 return NULL;
00367 }
00368 }
00369
00370
00371
00372 std::string EncodeXMLString(const XS_String& str, bool cdata)
00373 {
00374 LPCXSSTR s = str.c_str();
00375 size_t l = XS_len(s);
00376
00377 if (cdata) {
00378
00379 std::string ret = CDATA_START;
00380
00381 #ifdef XS_STRING_UTF8
00382 ret += str;
00383 #else
00384 ret += get_utf8(str);
00385 #endif
00386
00387 ret += CDATA_END;
00388
00389 return ret;
00390 } else if (l <= BUFFER_LEN) {
00391 LPXSSTR buffer = (LPXSSTR)alloca(6*sizeof(XS_CHAR)*XS_len(s));
00392 LPXSSTR o = buffer;
00393
00394 for(LPCXSSTR p=s; *p; ++p)
00395 switch(*p) {
00396 case '&':
00397 *o++ = '&'; *o++ = 'a'; *o++ = 'm'; *o++ = 'p'; *o++ = ';';
00398 break;
00399
00400 case '<':
00401 *o++ = '&'; *o++ = 'l'; *o++ = 't'; *o++ = ';';
00402 break;
00403
00404 case '>':
00405 *o++ = '&'; *o++ = 'g'; *o++ = 't'; *o++ = ';';
00406 break;
00407
00408 case '"':
00409 *o++ = '&'; *o++ = 'q'; *o++ = 'u'; *o++ = 'o'; *o++ = 't'; *o++ = ';';
00410 break;
00411
00412 case '\'':
00413 *o++ = '&'; *o++ = 'a'; *o++ = 'p'; *o++ = 'o'; *o++ = 's'; *o++ = ';';
00414 break;
00415
00416 default:
00417 if ((unsigned)*p<0x20 && *p!='\t' && *p!='\r' && *p!='\n') {
00418 char b[16];
00419 sprintf(b, "&#%d;", (unsigned)*p);
00420 for(const char*q=b; *q; )
00421 *o++ = *q++;
00422 } else
00423 *o++ = *p;
00424 }
00425
00426 #ifdef XS_STRING_UTF8
00427 return XS_String(buffer, o-buffer);
00428 #else
00429 return get_utf8(buffer, o-buffer);
00430 #endif
00431 } else {
00432
00433
00434 fast_ostringstream out;
00435
00436 LPCXSSTR s = str.c_str();
00437
00438 for(LPCXSSTR p=s; *p; ++p)
00439 switch(*p) {
00440 case '&':
00441 out << "&";
00442 break;
00443
00444 case '<':
00445 out << "<";
00446 break;
00447
00448 case '>':
00449 out << ">";
00450 break;
00451
00452 case '"':
00453 out << """;
00454 break;
00455
00456 case '\'':
00457 out << "'";
00458 break;
00459
00460 default:
00461 if ((unsigned)*p<0x20 && *p!='\t' && *p!='\r' && *p!='\n')
00462 out << "&#" << (unsigned)*p << ";";
00463 else
00464 out << *p;
00465 }
00466
00467 #ifdef XS_STRING_UTF8
00468 return XS_String(out.str());
00469 #else
00470 return get_utf8(out.str());
00471 #endif
00472 }
00473 }
00474
00475
00476 XS_String DecodeXMLString(const std::string& str)
00477 {
00478 #ifdef XS_STRING_UTF8
00479 const XS_String& str_utf8 = str;
00480 #else
00481 XS_String str_utf8;
00482 assign_utf8(str_utf8, str.c_str(), str.length());
00483 #endif
00484
00485 LPCXSSTR s = str_utf8.c_str();
00486 LPXSSTR buffer = (LPXSSTR)alloca(sizeof(XS_CHAR)*XS_len(s));
00487 LPXSSTR o = buffer;
00488
00489 for(LPCXSSTR p=s; *p; ++p)
00490 if (*p == '&') {
00491 if (!XS_nicmp(p+1, XS_TEXT("lt;"), 3)) {
00492 *o++ = '<';
00493 p += 3;
00494 } else if (!XS_nicmp(p+1, XS_TEXT("gt;"), 3)) {
00495 *o++ = '>';
00496 p += 3;
00497 } else if (!XS_nicmp(p+1, XS_TEXT("amp;"), 4)) {
00498 *o++ = '&';
00499 p += 4;
00500 } else if (!XS_nicmp(p+1, XS_TEXT("quot;"), 5)) {
00501 *o++ = '"';
00502 p += 5;
00503 } else if (!XS_nicmp(p+1, XS_TEXT("apos;"), 5)) {
00504 *o++ = '\'';
00505 p += 5;
00506 } else
00507 *o++ = *p;
00508 } else if (*p=='<' && !XS_nicmp(p+1,XS_TEXT("![CDATA["),8)) {
00509 LPCXSSTR e = XS_strstr(p+9, XS_TEXT(CDATA_END));
00510 if (e) {
00511 p += 9;
00512 size_t l = e - p;
00513 memcpy(o, p, l);
00514 o += l;
00515 p = e + 2;
00516 } else
00517 *o++ = *p;
00518 } else
00519 *o++ = *p;
00520
00521 return XS_String(buffer, o-buffer);
00522 }
00523
00524
00525
00526 void XMLNode::original_write_worker(std::ostream& out) const
00527 {
00528 out << _leading << '<' << EncodeXMLString(*this);
00529
00530 for(AttributeMap::const_iterator it=_attributes.begin(); it!=_attributes.end(); ++it)
00531 out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\"";
00532
00533 if (!_children.empty() || !_content.empty()) {
00534 out << '>';
00535
00536 if (_cdata_content)
00537 out << CDATA_START << _content << CDATA_END;
00538 else
00539 out << _content;
00540
00541 for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it)
00542 (*it)->original_write_worker(out);
00543
00544 out << _end_leading << "</" << EncodeXMLString(*this) << '>';
00545 } else
00546 out << "/>";
00547
00548 out << _trailing;
00549 }
00550
00551
00552
00553 void XMLNode::plain_write_worker(std::ostream& out) const
00554 {
00555 out << '<' << EncodeXMLString(*this);
00556
00557 for(AttributeMap::const_iterator it=_attributes.begin(); it!=_attributes.end(); ++it)
00558 out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\"";
00559
00560
00561 const char* content = _content.c_str();
00562 while(isspace((unsigned char)*content)) ++content;
00563
00564 if (!_children.empty() || *content) {
00565 out << ">" << content;
00566
00567 for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it)
00568 (*it)->plain_write_worker(out);
00569
00570 out << "</" << EncodeXMLString(*this) << ">";
00571 } else
00572 out << "/>";
00573 }
00574
00575
00576
00577 void XMLNode::pretty_write_worker(std::ostream& out, const XMLFormat& format, int indent) const
00578 {
00579 for(int i=indent; i--; )
00580 out << XML_INDENT_SPACE;
00581
00582 out << '<' << EncodeXMLString(*this);
00583
00584 for(AttributeMap::const_iterator it=_attributes.begin(); it!=_attributes.end(); ++it)
00585 out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\"";
00586
00587
00588 const char* content = _content.c_str();
00589 while(isspace((unsigned char)*content)) ++content;
00590
00591 if (!_children.empty() || *content) {
00592 out << '>' << content;
00593
00594 if (!_children.empty())
00595 out << format._endl;
00596
00597 for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it)
00598 (*it)->pretty_write_worker(out, format, indent+1);
00599
00600 for(int i=indent; i--; )
00601 out << XML_INDENT_SPACE;
00602
00603 out << "</" << EncodeXMLString(*this) << '>' << format._endl;
00604 } else
00605 out << "/>" << format._endl;
00606 }
00607
00608
00609
00610 void XMLNode::smart_write_worker(std::ostream& out, const XMLFormat& format, int indent) const
00611 {
00612
00613 const char* leading = _leading.c_str();
00614 if (*leading == '\n') ++leading;
00615
00616 if (!*leading)
00617 for(int i=indent; i--; )
00618 out << XML_INDENT_SPACE;
00619 else
00620 out << leading;
00621
00622 out << '<' << EncodeXMLString(*this);
00623
00624 for(AttributeMap::const_iterator it=_attributes.begin(); it!=_attributes.end(); ++it)
00625 out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\"";
00626
00627
00628 const char* content = _content.c_str();
00629 while(isspace((unsigned char)*content)) ++content;
00630
00631 if (_children.empty() && !*content)
00632 out << "/>";
00633 else {
00634 out << '>';
00635
00636 if (_cdata_content)
00637 out << CDATA_START << _content << CDATA_END;
00638 else if (!*content)
00639 out << format._endl;
00640 else
00641 out << content;
00642
00643 Children::const_iterator it = _children.begin();
00644
00645 if (it != _children.end()) {
00646 for(; it!=_children.end(); ++it)
00647 (*it)->smart_write_worker(out, format, indent+1);
00648
00649
00650 const char* end_leading = _end_leading.c_str();
00651 if (*end_leading == '\n') ++end_leading;
00652
00653 if (!*end_leading)
00654 for(int i=indent; i--; )
00655 out << XML_INDENT_SPACE;
00656 else
00657 out << end_leading;
00658 } else
00659 out << _end_leading;
00660
00661 out << "</" << EncodeXMLString(*this) << '>';
00662 }
00663
00664 if (_trailing.empty())
00665 out << format._endl;
00666 else
00667 out << _trailing;
00668 }
00669
00670
00671 std::ostream& operator<<(std::ostream& out, const XMLError& err)
00672 {
00673 out << err._systemId << "(" << err._line << ") [column " << err._column << "] : "
00674 << err._message;
00675
00676 return out;
00677 }
00678
00679
00680 const char* get_xmlsym_end_utf8(const char* p)
00681 {
00682 for(; *p; ++p) {
00683 char c = *p;
00684
00685
00686 if (c == '\xC3')
00687 ++p;
00688 else if (!isalnum(c) && c!='.' && c!='-' && c!='_' && c!=':')
00689 break;
00690 }
00691
00692 return p;
00693 }
00694
00695
00696 void DocType::parse(const char* p)
00697 {
00698 while(isspace((unsigned char)*p)) ++p;
00699
00700 const char* start = p;
00701 p = get_xmlsym_end_utf8(p);
00702 _name.assign(start, p-start);
00703
00704 while(isspace((unsigned char)*p)) ++p;
00705
00706 start = p;
00707 p = get_xmlsym_end_utf8(p);
00708 std::string keyword(p, p-start);
00709
00710 while(isspace((unsigned char)*p)) ++p;
00711
00712 if (*p=='"' || *p=='\'') {
00713 char delim = *p;
00714
00715 start = ++p;
00716 while(*p && *p!=delim) ++p;
00717
00718 if (*p == delim)
00719 _public.assign(start, p++-start);
00720 } else
00721 _public.erase();
00722
00723 while(isspace((unsigned char)*p)) ++p;
00724
00725 if (*p=='"' || *p=='\'') {
00726 char delim = *p;
00727
00728 start = ++p;
00729 while(*p && *p!=delim) ++p;
00730
00731 if (*p == delim)
00732 _system.assign(start, p++-start);
00733 } else
00734 _system.erase();
00735 }
00736
00737
00738 void XMLFormat::print_header(std::ostream& out, bool lf) const
00739 {
00740 out << "<?xml version=\"" << _version << "\" encoding=\"" << _encoding << "\"";
00741
00742 if (_standalone != -1)
00743 out << " standalone=\"yes\"";
00744
00745 out << "?>";
00746
00747 if (lf)
00748 out << _endl;
00749
00750 if (!_doctype.empty()) {
00751 out << "<!DOCTYPE " << _doctype._name;
00752
00753 if (!_doctype._public.empty()) {
00754 out << " PUBLIC \"" << _doctype._public << '"';
00755
00756 if (lf)
00757 out << _endl;
00758
00759 out << " \"" << _doctype._system << '"';
00760 } else if (!_doctype._system.empty())
00761 out << " SYSTEM \"" << _doctype._system << '"';
00762
00763 out << "?>";
00764
00765 if (lf)
00766 out << _endl;
00767 }
00768
00769 for(StyleSheetList::const_iterator it=_stylesheets.begin(); it!=_stylesheets.end(); ++it) {
00770 it->print(out);
00771
00772 if (lf)
00773 out << _endl;
00774 }
00775
00776
00777
00778
00779
00780
00781
00782 }
00783
00784 void StyleSheet::print(std::ostream& out) const
00785 {
00786 out << "<?xml-stylesheet"
00787 " href=\"" << _href << "\""
00788 " type=\"" << _type << "\"";
00789
00790 if (!_title.empty())
00791 out << " title=\"" << _title << "\"";
00792
00793 if (!_media.empty())
00794 out << " media=\"" << _media << "\"";
00795
00796 if (!_charset.empty())
00797 out << " charset=\"" << _charset << "\"";
00798
00799 if (_alternate)
00800 out << " alternate=\"yes\"";
00801
00802 out << "?>";
00803 }
00804
00805
00806
00807 std::string XMLError::str() const
00808 {
00809 std::ostringstream out;
00810
00811 out << *this;
00812
00813 return out.str();
00814 }
00815
00816
00817
00818 XS_String XMLErrorList::str() const
00819 {
00820 std::ostringstream out;
00821
00822 for(const_iterator it=begin(); it!=end(); ++it)
00823 out << *it << std::endl;
00824
00825 return out.str();
00826 }
00827
00828
00829 void XMLReaderBase::finish_read()
00830 {
00831 if (_pos->_children.empty())
00832 _pos->_trailing.append(_content);
00833 else
00834 _pos->_children.back()->_trailing.append(_content);
00835
00836 _content.erase();
00837 }
00838
00839
00840
00841 void XMLReaderBase::XmlDeclHandler(const char* version, const char* encoding, int standalone)
00842 {
00843 if (version)
00844 _format._version = version;
00845
00846 if (encoding)
00847 _format._encoding = encoding;
00848
00849 _format._standalone = standalone;
00850 }
00851
00852
00853
00854 void XMLReaderBase::StartElementHandler(const XS_String& name, const XMLNode::AttributeMap& attributes)
00855 {
00856 const char* s = _content.c_str();
00857 const char* e = s + _content.length();
00858 const char* p = s;
00859
00860
00861 for(p=e; p>s; --p)
00862 if (!isspace((unsigned char)p[-1]))
00863 break;
00864
00865 if (p != s) {
00866 if (_pos->_children.empty()) {
00867 if (_last_tag == TAG_START)
00868 _pos->_content.append(s, p-s);
00869 else if (_last_tag == TAG_END)
00870 _pos->_trailing.append(s, p-s);
00871 else
00872 p = s;
00873 } else
00874 _pos->_children.back()->_trailing.append(s, p-s);
00875 }
00876
00877 std::string leading;
00878
00879 if (p != e)
00880 leading.assign(p, e-p);
00881
00882 XMLNode* node = new XMLNode(name, leading);
00883
00884 _pos.add_down(node);
00885
00886 #ifdef XMLNODE_LOCATION
00887 node->_location = get_location();
00888 #endif
00889
00890 node->_attributes = attributes;
00891
00892 _last_tag = TAG_START;
00893 _content.erase();
00894 }
00895
00896
00897 void XMLReaderBase::EndElementHandler()
00898 {
00899 const char* s = _content.c_str();
00900 const char* e = s + _content.length();
00901 const char* p;
00902
00903 if (!strncmp(s,CDATA_START,9) && !strncmp(e-3,CDATA_END,3)) {
00904 s += 9;
00905 p = (e-=3);
00906
00907 _pos->_cdata_content = true;
00908 } else {
00909
00910 for(p=e; p>s; --p)
00911 if (!isspace((unsigned char)p[-1]))
00912 break;
00913
00914 _pos->_cdata_content = false;
00915 }
00916
00917 if (p != s) {
00918 if (_pos->_children.empty())
00919 _pos->_content.append(s, p-s);
00920 else if (_last_tag == TAG_START)
00921 _pos->_content.append(s, p-s);
00922 else
00923 _pos->_children.back()->_trailing.append(s, p-s);
00924 }
00925
00926 if (p != e)
00927 _pos->_end_leading.assign(p, e-p);
00928
00929 _pos.back();
00930
00931 _last_tag = TAG_END;
00932 _content.erase();
00933 }
00934
00935 #if defined(XS_USE_XERCES) || defined(XS_USE_EXPAT)
00936
00937 void XMLReaderBase::DefaultHandler(const XML_Char* s, int len)
00938 {
00939 #if defined(XML_UNICODE) || defined(XS_USE_XERCES)
00940 _content.append(String_from_XML_Char(s, len));
00941 #else
00942 _content.append(s, len);
00943 #endif
00944 }
00945 #endif
00946
00947
00948 XS_String XMLWriter::s_empty_attr;
00949
00950 void XMLWriter::create(const XS_String& name)
00951 {
00952 if (!_stack.empty()) {
00953 StackEntry& last = _stack.top();
00954
00955 if (last._state < PRE_CLOSED) {
00956 write_attributes(last);
00957 close_pre(last);
00958 }
00959
00960 ++last._children;
00961 }
00962
00963 StackEntry entry;
00964 entry._node_name = name;
00965 _stack.push(entry);
00966
00967 write_pre(entry);
00968 }
00969
00970 bool XMLWriter::back()
00971 {
00972 if (!_stack.empty()) {
00973 write_post(_stack.top());
00974
00975 _stack.pop();
00976 return true;
00977 } else
00978 return false;
00979 }
00980
00981 void XMLWriter::close_pre(StackEntry& entry)
00982 {
00983 _out << '>';
00984
00985 entry._state = PRE_CLOSED;
00986 }
00987
00988 void XMLWriter::write_pre(StackEntry& entry)
00989 {
00990 if (_format._pretty >= PRETTY_LINEFEED)
00991 _out << _format._endl;
00992
00993 if (_format._pretty == PRETTY_INDENT) {
00994 for(size_t i=_stack.size(); --i>0; )
00995 _out << XML_INDENT_SPACE;
00996 }
00997
00998 _out << '<' << EncodeXMLString(entry._node_name);
00999
01000 }
01001
01002 void XMLWriter::write_attributes(StackEntry& entry)
01003 {
01004 for(AttrMap::const_iterator it=entry._attributes.begin(); it!=entry._attributes.end(); ++it)
01005 _out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\"";
01006
01007 entry._state = ATTRIBUTES;
01008 }
01009
01010 void XMLWriter::write_post(StackEntry& entry)
01011 {
01012 if (entry._state < ATTRIBUTES)
01013 write_attributes(entry);
01014
01015 if (entry._children || !entry._content.empty()) {
01016 if (entry._state < PRE_CLOSED)
01017 close_pre(entry);
01018
01019 _out << entry._content;
01020
01021
01022 if (_format._pretty>=PRETTY_LINEFEED && entry._content.empty())
01023 _out << _format._endl;
01024
01025 if (_format._pretty==PRETTY_INDENT && entry._content.empty()) {
01026 for(size_t i=_stack.size(); --i>0; )
01027 _out << XML_INDENT_SPACE;
01028 }
01029
01030 _out << "</" << EncodeXMLString(entry._node_name) << ">";
01031 } else {
01032 _out << "/>";
01033 }
01034
01035 entry._state = POST;
01036 }
01037
01038
01039 }