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_INT64FMT = XS_INT64FMT_STR;
00057 const LPCXSSTR XS_FLOATFMT = XS_FLOATFMT_STR;
00058 #endif
00059
00060 const XS_String XS_KEY = XS_KEY_STR;
00061 const XS_String XS_VALUE = XS_VALUE_STR;
00062 const XS_String XS_PROPERTY = XS_PROPERTY_STR;
00063
00064
00065
00066 static XS_String unescape(LPCXSSTR s, TCHAR b, TCHAR e)
00067 {
00068 if (*s == b) {
00069 LPCXSSTR end = s + _tcslen(s);
00070
00071 if (end>s && end[-1]==e)
00072 ++s, --end;
00073
00074 return XS_String(s, end-s);
00075 } else
00076 return s;
00077 }
00078
00079 inline XS_String unescape(LPCXSSTR s)
00080 {
00081 if (*s == TEXT('\''))
00082 return unescape(s, TEXT('\''), TEXT('\''));
00083 else
00084 return unescape(s, TEXT('"'), TEXT('"'));
00085 }
00086
00087
00088 static XS_String unescape(LPCXSSTR s, size_t l, char b, char e)
00089 {
00090 LPCXSSTR end = s + l;
00091
00092 if (*s == b)
00093 if (end>s+1 && end[-1]==e)
00094 ++s, --end;
00095
00096 return XS_String(s, end-s);
00097 }
00098
00099 inline XS_String unescape(LPCXSSTR s, size_t l)
00100 {
00101 if (*s == '\'')
00102 return unescape(s, l, TEXT('\''), TEXT('\''));
00103 else if (*s == '"')
00104 return unescape(s, l, TEXT('"'), TEXT('"'));
00105 else
00106 return XS_String(s, l);
00107 }
00108
00109
00110
00111 bool XMLPos::go(const XPath& xpath)
00112 {
00113 XMLNode* node = xpath._absolute? _root: _cur;
00114
00115 node = node->find_relative(xpath);
00116
00117 if (node) {
00118 go_to(node);
00119 return true;
00120 } else
00121 return false;
00122 }
00123
00124
00125 bool const_XMLPos::go(const XPath& xpath)
00126 {
00127 const XMLNode* node = xpath._absolute? _root: _cur;
00128
00129 node = node->find_relative(xpath);
00130
00131 if (node) {
00132 go_to(node);
00133 return true;
00134 } else
00135 return false;
00136 }
00137
00138
00139 LPCXSSTR XPathElement::parse(LPCXSSTR path)
00140 {
00141 LPCXSSTR slash = _tcschr(path, '/');
00142 if (slash == path)
00143 return NULL;
00144
00145
00146 size_t l = slash? slash-path: _tcslen(path);
00147 XS_String comp(path, l);
00148 path += l;
00149
00150
00151 LPCXSSTR bracket = _tcschr(comp.c_str(), TEXT('['));
00152 l = bracket? bracket-comp.c_str(): comp.length();
00153 _child_name.assign(comp.c_str(), l);
00154
00155 if (bracket) {
00156 XS_String expr = unescape(bracket, TEXT('['), TEXT(']'));
00157 LPCXSSTR p = expr.c_str();
00158
00159 while(_istspace((_TUCHAR)*p)) ++p;
00160
00161 if (isdigit(*p)) {
00162 int n = _ttoi(p);
00163
00164 if (n)
00165 _child_idx = n - 1;
00166 } else {
00167 while(*p == '@') {
00168 LPCXSSTR equal = _tcschr(++p, '=');
00169
00170 if (equal) {
00171
00172
00173 LPCXSSTR del1 = equal+1;
00174 LPCXSSTR del2 = *del1==TEXT('\'')||*del1==TEXT('"')? _tcschr(del1+1, *del1): NULL;
00175
00176
00177 const XS_String& attrName = unescape(p, equal-p);
00178 const XS_String& attrValue = del2? unescape(del1, ++del2-del1): unescape(del1);
00179
00180 _mAttrAndAttr[attrName] = attrValue;
00181
00182 if (!del2)
00183 break;
00184
00185 p = del2 + 1;
00186 while(isspace((unsigned char)*p)) ++p;
00187
00188
00189
00190 if (!_tcsnicmp(p, XS_TEXT("and "), 4))
00191 p += 4;
00192 }
00193
00194 while(_istspace((_TUCHAR)*p)) ++p;
00195 }
00196 }
00197 }
00198
00199 return path;
00200 }
00201
00202 XMLNode* XPathElement::find(XMLNode* node) const
00203 {
00204 int n = 0;
00205
00206 for(XMLNode::Children::const_iterator it=node->_children.begin(); it!=node->_children.end(); ++it)
00207 if (matches(**it, n))
00208 return *it;
00209
00210 return NULL;
00211 }
00212
00213 const XMLNode* XPathElement::const_find(const XMLNode* node) const
00214 {
00215 int n = 0;
00216
00217 for(XMLNode::Children::const_iterator it=node->_children.begin(); it!=node->_children.end(); ++it)
00218 if (matches(**it, n))
00219 return *it;
00220
00221 return NULL;
00222 }
00223
00224 bool XPathElement::matches(const XMLNode& node, int& n) const
00225 {
00226 if (node != _child_name)
00227 if (_child_name != XS_TEXT("*"))
00228 return false;
00229
00230 for(MAPATTR::const_iterator b=_mAttrAndAttr.begin(), e=_mAttrAndAttr.end(); b!=e; ++b)
00231 if (node.get(b->first) != b->second)
00232 return false;
00233
00234 if (_child_idx == -1)
00235 return true;
00236 else if (n++ == _child_idx)
00237 return true;
00238 else
00239 return false;
00240 }
00241
00242
00243 void XPath::init(LPCXSSTR path)
00244 {
00245
00246 if (*path == '/') {
00247 _absolute = true;
00248 ++path;
00249 } else
00250 _absolute = false;
00251
00252
00253 while(*path) {
00254 XPathElement elem;
00255
00256 path = elem.parse(path);
00257
00258 if (!path)
00259 break;
00260
00261 push_back(elem);
00262
00263 if (*path == '/')
00264 ++path;
00265 }
00266 }
00267
00268
00269 const XMLNode* XMLNode::find_relative(const XPath& xpath) const
00270 {
00271 const XMLNode* node = this;
00272
00273 for(XPath::const_iterator it=xpath.begin(); it!=xpath.end(); ++it) {
00274 node = it->const_find(node);
00275
00276 if (!node)
00277 break;
00278 }
00279
00280 return node;
00281 }
00282
00283 XMLNode* XMLNode::find_relative(const XPath& xpath)
00284 {
00285 XMLNode* node = this;
00286
00287 for(XPath::const_iterator it=xpath.begin(); it!=xpath.end(); ++it) {
00288 node = it->find(node);
00289
00290 if (!node)
00291 break;
00292 }
00293
00294 return node;
00295 }
00296
00297 XMLNode* XMLNode::create_relative(const XPath& xpath)
00298 {
00299 XMLNode* node = this;
00300
00301 for(XPath::const_iterator it=xpath.begin(); it!=xpath.end(); ++it) {
00302 XMLNode* child = it->find(node);
00303
00304 if (!child) {
00305 child = new XMLNode(it->_child_name);
00306 node->add_child(child);
00307
00308 for(XPathElement::MAPATTR::const_iterator b=it->_mAttrAndAttr.begin(), e=it->_mAttrAndAttr.end(); b!=e; ++b)
00309 (*this)[b->first] = b->second;
00310 }
00311
00312 node = child;
00313 }
00314
00315 return node;
00316 }
00317
00318
00319 int XMLNode::count(XPath::const_iterator from, const XPath::const_iterator& to) const
00320 {
00321 const XPathElement& elem = *from++;
00322 int cnt = 0;
00323 int n = 0;
00324
00325 for(XMLNode::Children::const_iterator it=_children.begin(); it!=_children.end(); ++it)
00326 if (elem.matches(**it, n)) {
00327 if (from != to)
00328
00329 cnt += (*it)->count(from, to);
00330 else
00331
00332 ++cnt;
00333 }
00334
00335 return cnt;
00336 }
00337
00338
00339 bool XMLNode::filter(const XPath& xpath, XMLNode& target) const
00340 {
00341 XMLNode* ret = filter(xpath.begin(), xpath.end());
00342 if (!ret)
00343 return false;
00344
00345
00346 target._children.move(ret->_children);
00347 target._attributes = ret->_attributes;
00348
00349 delete ret;
00350
00351 return true;
00352 }
00353
00354
00355 XMLNode* XMLNode::filter(XPath::const_iterator from, const XPath::const_iterator& to) const
00356 {
00357 XMLNode* copy = NULL;
00358
00359 const XPathElement& elem = *from++;
00360 int cnt = 0;
00361 int n = 0;
00362
00363 for(XMLNode::Children::const_iterator it=_children.begin(); it!=_children.end(); ++it)
00364 if (elem.matches(**it, n)) {
00365 if (!copy)
00366 copy = new XMLNode(*this, XMLNode::COPY_NOCHILDREN);
00367
00368 if (from != to) {
00369 XMLNode* ret = (*it)->filter(from, to);
00370
00371 if (ret) {
00372 copy->add_child(ret);
00373 ++cnt;
00374 }
00375 } else {
00376 copy->add_child(new XMLNode(**it, XMLNode::COPY_NOCHILDREN));
00377 ++cnt;
00378 }
00379 }
00380
00381 if (!cnt) {
00382 delete copy;
00383 copy = NULL;
00384 }
00385
00386 return copy;
00387 }
00388
00389
00390
00391 std::string EncodeXMLString(const XS_String& str, bool cdata)
00392 {
00393 LPCXSSTR s = str.c_str();
00394 size_t l = XS_len(s);
00395
00396 if (cdata) {
00397
00398 std::string ret = CDATA_START;
00399
00400 #ifdef XS_STRING_UTF8
00401 ret += str;
00402 #else
00403 ret += get_utf8(str);
00404 #endif
00405
00406 #ifdef XS_STRICT_XML_1_0
00407 for(char*p=&ret.at(9); *p; ++p)
00408 if ((unsigned)*p<0x20 && *p!='\t' && *p!='\r' && *p!='\n')
00409 *p = '?';
00410 #endif
00411
00412 ret += CDATA_END;
00413
00414 return ret;
00415 } else if (l <= BUFFER_LEN) {
00416 LPXSSTR buffer = (LPXSSTR)alloca(6*sizeof(XS_CHAR)*XS_len(s));
00417 LPXSSTR o = buffer;
00418
00419 for(LPCXSSTR p=s; *p; ++p)
00420 switch(*p) {
00421 case '&':
00422 *o++ = '&'; *o++ = 'a'; *o++ = 'm'; *o++ = 'p'; *o++ = ';';
00423 break;
00424
00425 case '<':
00426 *o++ = '&'; *o++ = 'l'; *o++ = 't'; *o++ = ';';
00427 break;
00428
00429 case '>':
00430 *o++ = '&'; *o++ = 'g'; *o++ = 't'; *o++ = ';';
00431 break;
00432
00433 case '"':
00434 *o++ = '&'; *o++ = 'q'; *o++ = 'u'; *o++ = 'o'; *o++ = 't'; *o++ = ';';
00435 break;
00436
00437 case '\'':
00438 *o++ = '&'; *o++ = 'a'; *o++ = 'p'; *o++ = 'o'; *o++ = 's'; *o++ = ';';
00439 break;
00440
00441 default:
00442 if ((unsigned)*p>=0x20 || *p=='\t' || *p=='\r' || *p=='\n')
00443 *o++ = *p;
00444 else {
00445 #ifdef XS_STRICT_XML_1_0
00446 *o++ = '?';
00447 #else
00448 char b[16];
00449 sprintf(b, "&#%d;", (unsigned)*p);
00450 for(const char*q=b; *q; )
00451 *o++ = *q++;
00452 #endif
00453 }
00454 }
00455
00456 #ifdef XS_STRING_UTF8
00457 return XS_String(buffer, o-buffer);
00458 #else
00459 return get_utf8(buffer, o-buffer);
00460 #endif
00461 } else {
00462
00463
00464 fast_ostringstream out;
00465
00466 #ifdef XS_STRING_UTF8
00467 LPCXSSTR s = str.c_str();
00468 #else
00469 std::string utf8_str = get_utf8(str);
00470 const char* s = utf8_str.c_str();
00471 #endif
00472
00473 for(const char* p=s; *p; ++p)
00474 switch(*p) {
00475 case '&':
00476 out << "&";
00477 break;
00478
00479 case '<':
00480 out << "<";
00481 break;
00482
00483 case '>':
00484 out << ">";
00485 break;
00486
00487 case '"':
00488 out << """;
00489 break;
00490
00491 case '\'':
00492 out << "'";
00493 break;
00494
00495 default:
00496 if ((unsigned)*p>=0x20 || *p=='\t' || *p=='\r' || *p=='\n')
00497 out << (unsigned char)*p;
00498 else {
00499 #ifdef XS_STRICT_XML_1_0
00500 out << '?';
00501 #else
00502 out << "&#" << (unsigned)*p << ";";
00503 #endif
00504 }
00505 }
00506
00507 #ifdef XS_STRING_UTF8
00508 return XS_String(out.str());
00509 #else
00510 return out.str();
00511 #endif
00512 }
00513 }
00514
00515
00516 XS_String DecodeXMLString(const std::string& str_utf8)
00517 {
00518 #ifdef XS_STRING_UTF8
00519 const XS_String& str = str_utf8;
00520 #else
00521 XS_String str;
00522 assign_utf8(str, str_utf8.c_str(), str_utf8.length());
00523 #endif
00524
00525 LPCXSSTR s = str.c_str();
00526 size_t l = XS_len(s);
00527
00528 TMP_ALLOC(XS_CHAR, buffer, heap, l);
00529
00530 LPXSSTR o = buffer;
00531 for(LPCXSSTR p=s; *p; ++p)
00532 if (*p == '&') {
00533 if (!XS_nicmp(p+1, XS_TEXT("lt;"), 3)) {
00534 *o++ = '<';
00535 p += 3;
00536 } else if (!XS_nicmp(p+1, XS_TEXT("gt;"), 3)) {
00537 *o++ = '>';
00538 p += 3;
00539 } else if (!XS_nicmp(p+1, XS_TEXT("amp;"), 4)) {
00540 *o++ = '&';
00541 p += 4;
00542 } else if (!XS_nicmp(p+1, XS_TEXT("quot;"), 5)) {
00543 *o++ = '"';
00544 p += 5;
00545 } else if (!XS_nicmp(p+1, XS_TEXT("apos;"), 5)) {
00546 *o++ = '\'';
00547 p += 5;
00548 } else
00549 *o++ = *p;
00550 } else if (*p=='<' && !XS_nicmp(p+1,XS_TEXT("![CDATA["),8)) {
00551 LPCXSSTR e = XS_strstr(p+9, XS_TEXT(CDATA_END));
00552 if (e) {
00553 p += 9;
00554 size_t l = e - p;
00555 memcpy(o, p, l);
00556 o += l;
00557 p = e + 2;
00558 } else
00559 *o++ = *p;
00560 } else
00561 *o++ = *p;
00562
00563 return XS_String(buffer, o-buffer);
00564 }
00565
00566
00567
00568 void XMLNode::original_write_worker(std::ostream& out) const
00569 {
00570 out << _leading << '<' << EncodeXMLString(*this);
00571
00572 for(AttributeMap::const_iterator it=_attributes.begin(); it!=_attributes.end(); ++it)
00573 out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\"";
00574
00575 if (!_children.empty() || !_content.empty()) {
00576 out << '>';
00577
00578 if (_cdata_content)
00579 out << CDATA_START << _content << CDATA_END;
00580 else
00581 out << _content;
00582
00583 for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it)
00584 (*it)->original_write_worker(out);
00585
00586 out << _end_leading << "</" << EncodeXMLString(*this) << '>';
00587 } else
00588 out << "/>";
00589
00590 out << _trailing;
00591 }
00592
00593
00594
00595 void XMLNode::plain_write_worker(std::ostream& out) const
00596 {
00597 out << '<' << EncodeXMLString(*this);
00598
00599 for(AttributeMap::const_iterator it=_attributes.begin(); it!=_attributes.end(); ++it)
00600 out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\"";
00601
00602 // strip leading white space from content
00603 const char* content = _content.c_str();
00604 while(isspace((unsigned char)*content)) ++content;
00605
00606 if (!_children.empty() || *content) {
00607 out << ">" << content;
00608
00609 for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it)
00610 (*it)->plain_write_worker(out);
00611
00612 out << "</" << EncodeXMLString(*this) << ">";
00613 } else
00614 out << "/>";
00615 }
00616
00617
00618
00619 void XMLNode::pretty_write_worker(std::ostream& out, const XMLFormat& format, int indent) const
00620 {
00621 for(int i=indent; i--; )
00622 out << XML_INDENT_SPACE;
00623
00624 out << '<' << EncodeXMLString(*this);
00625
00626 for(AttributeMap::const_iterator it=_attributes.begin(); it!=_attributes.end(); ++it)
00627 out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\"";
00628
00629 // strip leading white space from content
00630 const char* content = _content.c_str();
00631 while(isspace((unsigned char)*content)) ++content;
00632
00633 if (!_children.empty() || *content) {
00634 out << '>' << content;
00635
00636 if (!_children.empty())
00637 out << format._endl;
00638
00639 for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it)
00640 (*it)->pretty_write_worker(out, format, indent+1);
00641
00642 for(int i=indent; i--; )
00643 out << XML_INDENT_SPACE;
00644
00645 out << "</" << EncodeXMLString(*this) << '>' << format._endl;
00646 } else
00647 out << "/>" << format._endl;
00648 }
00649
00650
00651
00652 void XMLNode::smart_write_worker(std::ostream& out, const XMLFormat& format, int indent) const
00653 {
00654 // strip the first line feed from _leading
00655 const char* leading = _leading.c_str();
00656 if (*leading == '\n') ++leading;
00657
00658 if (!*leading)
00659 for(int i=indent; i--; )
00660 out << XML_INDENT_SPACE;
00661 else
00662 out << leading;
00663
00664 out << '<' << EncodeXMLString(*this);
00665
00666 for(AttributeMap::const_iterator it=_attributes.begin(); it!=_attributes.end(); ++it)
00667 out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\"";
00668
00669 // strip leading white space from content
00670 const char* content = _content.c_str();
00671 while(isspace((unsigned char)*content)) ++content;
00672
00673 if (_children.empty() && !*content)
00674 out << "/>";
00675 else {
00676 out << '>';
00677
00678 if (_cdata_content)
00679 out << CDATA_START << _content << CDATA_END;
00680 else if (!*content)
00681 out << format._endl;
00682 else
00683 out << content;
00684
00685 Children::const_iterator it = _children.begin();
00686
00687 if (it != _children.end()) {
00688 for(; it!=_children.end(); ++it)
00689 (*it)->smart_write_worker(out, format, indent+1);
00690
00691 // strip the first line feed from _end_leading
00692 const char* end_leading = _end_leading.c_str();
00693 if (*end_leading == '\n') ++end_leading;
00694
00695 if (!*end_leading)
00696 for(int i=indent; i--; )
00697 out << XML_INDENT_SPACE;
00698 else
00699 out << end_leading;
00700 } else
00701 out << _end_leading;
00702
00703 out << "</" << EncodeXMLString(*this) << '>';
00704 }
00705
00706 if (_trailing.empty())
00707 out << format._endl;
00708 else
00709 out << _trailing;
00710 }
00711
00712
00713 std::ostream& operator<<(std::ostream& out, const XMLError& err)
00714 {
00715 out << err._systemId << "(" << err._line << ")";
00716
00717 if (err._column > 1)
00718 out << " [column " << err._column << "]";
00719
00720 out << " : " << err._message;
00721
00722 return out;
00723 }
00724
00725
00726 #if defined(XS_NATIVE) || defined(XMLNODE_LOCATION)
00727
00728 std::string XMLLocation::str() const
00729 {
00730 std::ostringstream out;
00731
00732 if (_pdisplay_path)
00733 out << _pdisplay_path;
00734
00735 out << "(" << _line << ")";
00736
00737 if (_column > 1)
00738 out << " [column " << _column << "]";
00739
00740 out << " :";
00741
00742 return out.str();
00743 }
00744
00745 #endif
00746
00747
00748 const char* get_xmlsym_end_utf8(const char* p)
00749 {
00750 for(; *p; ++p) {
00751 char c = *p;
00752
00753 // NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | CombiningChar | Extender
00754 if (c == '\xC3') // UTF-8 escape character
00755 ++p; //TODO only continue on umlaut characters
00756 else if (!isalnum(c) && c!='.' && c!='-' && c!='_' && c!=':')
00757 break;
00758 }
00759
00760 return p;
00761 }
00762
00763
00764 void DocType::parse(const char* p)
00765 {
00766 while(isspace((unsigned char)*p)) ++p;
00767
00768 const char* start = p;
00769 p = get_xmlsym_end_utf8(p);
00770 _name.assign(start, p-start);
00771
00772 while(isspace((unsigned char)*p)) ++p;
00773
00774 start = p;
00775 p = get_xmlsym_end_utf8(p);
00776 // std::string keyword(p, p-start); // "PUBLIC" or "SYSTEM"
00777
00778 while(isspace((unsigned char)*p)) ++p;
00779
00780 if (*p=='"' || *p=='\'') {
00781 char delim = *p;
00782
00783 start = ++p;
00784 while(*p && *p!=delim) ++p;
00785
00786 if (*p == delim)
00787 _public.assign(start, p++-start);
00788 } else
00789 _public.erase();
00790
00791 while(isspace((unsigned char)*p)) ++p;
00792
00793 if (*p=='"' || *p=='\'') {
00794 char delim = *p;
00795
00796 start = ++p;
00797 while(*p && *p!=delim) ++p;
00798
00799 if (*p == delim)
00800 _system.assign(start, p++-start);
00801 } else
00802 _system.erase();
00803 }
00804
00805
00806 void XMLFormat::print_header(std::ostream& out, bool lf) const
00807 {
00808 if (_inhibit_header)
00809 return;
00810
00811 if (_utf8_bom) {
00812
00813 out.put('\xEF');
00814 out.put('\xBB');
00815 out.put('\xBF');
00816 assert(!_stricmp(_encoding.c_str(), "utf-8"));
00817 }
00818
00819 out << "<?xml version=\"" << _version << "\" encoding=\"" << _encoding << "\"";
00820
00821 if (_standalone != -1)
00822 out << " standalone=\"yes\"";
00823
00824 out << "?>";
00825
00826 if (lf)
00827 out << _endl;
00828
00829 if (!_doctype.empty()) {
00830 out << "<!DOCTYPE " << _doctype._name;
00831
00832 if (!_doctype._public.empty()) {
00833 out << " PUBLIC \"" << _doctype._public << '"';
00834
00835 if (lf)
00836 out << _endl;
00837
00838 out << " \"" << _doctype._system << '"';
00839 } else if (!_doctype._system.empty())
00840 out << " SYSTEM \"" << _doctype._system << '"';
00841
00842 out << "?>";
00843
00844 if (lf)
00845 out << _endl;
00846 }
00847
00848 for(StyleSheetList::const_iterator it=_stylesheets.begin(); it!=_stylesheets.end(); ++it) {
00849 it->print(out);
00850
00851 if (lf)
00852 out << _endl;
00853 }
00854
00855
00856
00857
00858
00859
00860
00861 }
00862
00863 void StyleSheet::print(std::ostream& out) const
00864 {
00865 out << "<?xml-stylesheet"
00866 " href=\"" << _href << "\""
00867 " type=\"" << _type << "\"";
00868
00869 if (!_title.empty())
00870 out << " title=\"" << _title << "\"";
00871
00872 if (!_media.empty())
00873 out << " media=\"" << _media << "\"";
00874
00875 if (!_charset.empty())
00876 out << " charset=\"" << _charset << "\"";
00877
00878 if (_alternate)
00879 out << " alternate=\"yes\"";
00880
00881 out << "?>";
00882 }
00883
00884
00885
00886 std::string XMLError::str() const
00887 {
00888 std::ostringstream out;
00889
00890 out << *this;
00891
00892 return out.str();
00893 }
00894
00895
00896
00897 XS_String XMLErrorList::str(const char* del) const
00898 {
00899 std::ostringstream out;
00900
00901 for(const_iterator it=begin(); it!=end(); ++it)
00902 out << *it << del;
00903
00904 return out.str();
00905 }
00906
00907
00908 void XMLReaderBase::finish_read()
00909 {
00910 if (_pos != NULL) {
00911 if (_pos->_children.empty())
00912 _pos->_trailing.append(_content);
00913 else
00914 _pos->_children.back()->_trailing.append(_content);
00915 }
00916
00917 _content.erase();
00918 }
00919
00920
00921
00922 void XMLReaderBase::XmlDeclHandler(const char* version, const char* encoding, int standalone)
00923 {
00924 if (version)
00925 _format._version = version;
00926
00927 if (encoding)
00928 _format._encoding = encoding;
00929
00930 _format._standalone = standalone;
00931 }
00932
00933
00934
00935 void XMLReaderBase::StartElementHandler(const XS_String& name, const XMLNode::AttributeMap& attributes)
00936 {
00937 const char* s = _content.c_str();
00938 const char* e = s + _content.length();
00939 const char* p = s;
00940
00941
00942 for(p=e; p>s; --p)
00943 if (!isspace((unsigned char)p[-1]))
00944 break;
00945
00946 if (p != s) {
00947 if (_pos->_children.empty()) {
00948 if (_last_tag == TAG_START)
00949 _pos->_content.append(s, p-s);
00950 else if (_last_tag == TAG_END)
00951 _pos->_trailing.append(s, p-s);
00952 else
00953 p = s;
00954 } else
00955 _pos->_children.back()->_trailing.append(s, p-s);
00956 }
00957
00958 std::string leading;
00959
00960 if (p != e)
00961 leading.assign(p, e-p);
00962
00963 XMLNode* node = new XMLNode(name, leading);
00964
00965 _pos.add_down(node);
00966
00967 #ifdef XMLNODE_LOCATION
00968 node->_location = get_location();
00969 #endif
00970
00971 node->_attributes = attributes;
00972
00973 _last_tag = TAG_START;
00974 _content.erase();
00975 }
00976
00977
00978 void XMLReaderBase::EndElementHandler()
00979 {
00980 const char* s = _content.c_str();
00981 const char* e = s + _content.length();
00982 const char* p;
00983
00984 if (!strncmp(s,CDATA_START,9) && !strncmp(e-3,CDATA_END,3)) {
00985 s += 9;
00986 p = (e-=3);
00987
00988 _pos->_cdata_content = true;
00989 } else {
00990
00991 for(p=e; p>s; --p)
00992 if (!isspace((unsigned char)p[-1]))
00993 break;
00994
00995 _pos->_cdata_content = false;
00996 }
00997
00998 if (p != s) {
00999 if (_pos->_children.empty())
01000 _pos->_content.append(s, p-s);
01001 else if (_last_tag == TAG_START)
01002 _pos->_content.append(s, p-s);
01003 else
01004 _pos->_children.back()->_trailing.append(s, p-s);
01005 }
01006
01007 if (p != e)
01008 _pos->_end_leading.assign(p, e-p);
01009
01010 _pos.back();
01011
01012 _last_tag = TAG_END;
01013 _content.erase();
01014 }
01015
01016 #if defined(XS_USE_XERCES) || defined(XS_USE_EXPAT)
01017
01018 void XMLReaderBase::DefaultHandler(const XML_Char* s, int len)
01019 {
01020 #if defined(XML_UNICODE) || defined(XS_USE_XERCES)
01021 _content.append(String_from_XML_Char(s, len));
01022 #else
01023 _content.append(s, len);
01024 #endif
01025 }
01026 #endif
01027
01028
01029 XS_String XMLWriter::s_empty_attr;
01030
01031 void XMLWriter::create(const XS_String& name)
01032 {
01033 if (!_stack.empty()) {
01034 StackEntry& last = _stack.top();
01035
01036 if (last._state < PRE_CLOSED) {
01037 write_attributes(last);
01038 close_pre(last);
01039 }
01040
01041 ++last._children;
01042 }
01043
01044 StackEntry entry;
01045 entry._node_name = name;
01046 _stack.push(entry);
01047
01048 write_pre(entry);
01049 }
01050
01051 bool XMLWriter::back()
01052 {
01053 if (!_stack.empty()) {
01054 write_post(_stack.top());
01055
01056 _stack.pop();
01057 return true;
01058 } else {
01059 assert(!_stack.empty());
01060 return false;
01061 }
01062 }
01063
01064 void XMLWriter::close_pre(StackEntry& entry)
01065 {
01066 _out << '>';
01067
01068 entry._state = PRE_CLOSED;
01069 }
01070
01071 void XMLWriter::write_pre(StackEntry& entry)
01072 {
01073 if (_format._pretty >= PRETTY_LINEFEED)
01074 _out << _format._endl;
01075
01076 if (_format._pretty == PRETTY_INDENT) {
01077 for(size_t i=_stack.size(); --i>0; )
01078 _out << XML_INDENT_SPACE;
01079 }
01080
01081 _out << '<' << EncodeXMLString(entry._node_name);
01082 //entry._state = PRE;
01083 }
01084
01085 void XMLWriter::write_attributes(StackEntry& entry)
01086 {
01087 for(AttrMap::const_iterator it=entry._attributes.begin(); it!=entry._attributes.end(); ++it)
01088 _out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\"";
01089
01090 entry._state = ATTRIBUTES;
01091 }
01092
01093 void XMLWriter::write_post(StackEntry& entry)
01094 {
01095 if (entry._state < ATTRIBUTES)
01096 write_attributes(entry);
01097
01098 if (entry._children || !entry._content.empty()) {
01099 if (entry._state < PRE_CLOSED)
01100 close_pre(entry);
01101
01102 _out << entry._content;
01103 //entry._state = CONTENT;
01104
01105 if (_format._pretty>=PRETTY_LINEFEED && entry._content.empty())
01106 _out << _format._endl;
01107
01108 if (_format._pretty==PRETTY_INDENT && entry._content.empty()) {
01109 for(size_t i=_stack.size(); --i>0; )
01110 _out << XML_INDENT_SPACE;
01111 }
01112
01113 _out << "</" << EncodeXMLString(entry._node_name) << ">";
01114 } else {
01115 _out << "/>";
01116 }
01117
01118 entry._state = POST;
01119 }
01120
01121 void XMLWriter::write(const std::string& s)
01122 {
01123 if (!_stack.empty()) {
01124 StackEntry& last = _stack.top();
01125
01126 if (last._state < PRE_CLOSED) {
01127 write_attributes(last);
01128 close_pre(last);
01129 }
01130 }
01131
01132 _out.write(s.c_str(), s.length());
01133 }
01134
01135
01136
01137 bool XMLStreamReader::find_relative(const XPath& xpath)
01138 {
01139 for(XPath::const_iterator it=xpath.begin(); it!=xpath.end(); ++it) {
01140 const XPathElement& xelem = *it;
01141
01142 if (!find(xelem))
01143 return false;
01144 }
01145
01146 return true;
01147 }
01148
01149 bool XMLStreamReader::find_node(LPCXSSTR target_tag, int target_level, int min_level, bool stop_on_others)
01150 {
01151 bool found = false;
01152
01153 for(; _state_rdr.has_next(); _state_rdr.next()) {
01154 switch(_state_rdr._state) {
01155 case XMLStateReader::XSS_START_ELEMENT: {
01156 // stop parsing if we found the target node and its content is already processed.
01157 if (found)
01158 goto break_parsingLoop;
01159
01160 // check for match in target level and eventually node name
01161 if (_level+1 == target_level) {
01162 if (target_tag==NULL || _state_rdr._node_name==target_tag)
01163 found = true;
01164 else if (stop_on_others)
01165 return false;
01166 }
01167
01168 StartElementHandler(_state_rdr._node_name, _state_rdr._attrs);
01169 break;}
01170
01171 case XMLStateReader::XSS_ELEMENT:
01172 // stop parsing if we found the target node and its content is already processed.
01173 if (found)
01174 goto break_parsingLoop;
01175
01176 // check for match in target level and eventually node name
01177 if (_level+1 == target_level) {
01178 if (target_tag==NULL || _state_rdr._node_name==target_tag)
01179 found = true;
01180 else if (stop_on_others)
01181 return false;
01182 }
01183
01184 StartElementHandler(_state_rdr._node_name, _state_rdr._attrs);
01185 _state_rdr.next(); // advance to the next state
01186 // fall through...
01187
01188 case XMLStateReader::XSS_END_ELEMENT: {
01189 // stop parsing if we found the target node and its content is already processed.
01190 if (found)
01191 goto break_parsingLoop;
01192
01193 // stop before leaving the targeted level range; used by next_stop_on_others()
01194 if (_level == min_level)
01195 return false;
01196
01197 EndElementHandler();
01198
01199 // stop searching if the current level leaves the target range; used by back()
01200 if (_level < min_level) {
01201 _state_rdr.next();
01202 return false;
01203 }
01204 break;}
01205
01206 case XMLStateReader::XSS_CHARACTERS:
01207 // case XMLStateReader::XSS_COMMENT:
01208 // case XMLStateReader::XSS_SPACE:
01209 // case XMLStateReader::XSS_CDATA:
01210 DefaultHandler(_state_rdr.get_encoded_content());
01211 break;
01212
01213 // case XMLStateReader::XSS_PROCESSING_INSTRUCTION:
01214 // XmlDeclHandler();
01215 // break;
01216 }
01217 } break_parsingLoop:
01218
01219 if (found) {
01220 _node.set_encoded_content(_content);
01221 _content.erase();
01222 return true;
01223 } else
01224 return false;
01225 }
01226
01227 void XMLStreamReader::StartElementHandler(const XS_String& name, const XMLNode::AttributeMap& attr)
01228 {
01229 _node.assign(name);
01230 _node.get_attributes() = attr;
01231 _content.erase();
01232
01233 ++_level;
01234 }
01235
01236 void XMLStreamReader::EndElementHandler()
01237 {
01238 _node.clear();
01239 _node.get_attributes().clear();
01240 _content.erase();
01241
01242 --_level;
01243 }
01244
01245 void XMLStreamReader::DefaultHandler(const std::string& s)
01246 {
01247 _content.append(DecodeXMLString(s));
01248 }
01249
01250
01251 bool XMLStateReader::has_next()
01252 {
01253 while(_state == XSS_NONE)
01254 if (!_parse_ctx.proceed())
01255 break;
01256
01257 return _state != XSS_NONE;
01258 }
01259
01260 void XMLStateReader::next()
01261 {
01262 _state = XSS_NONE;
01263 _node_name.erase();
01264
01265 _parse_ctx.proceed();
01266 }
01267
01268 void XMLStateReader::StartElementHandler(const XS_String& name, const XMLNode::AttributeMap& attr)
01269 {
01270 _node_name = name;
01271 _attrs = attr;
01272 _content.erase();
01273
01274 assert(_state==XSS_NONE);
01275 _state = XSS_START_ELEMENT;
01276 }
01277
01278 void XMLStateReader::EndElementHandler()
01279 {
01280 // _node_name.erase();
01281 // _attrs.clear();
01282 _content.erase();
01283
01284 if (_state == XSS_START_ELEMENT)
01285 _state = XSS_ELEMENT;
01286 else {
01287 assert(_state==XSS_NONE);
01288 _state = XSS_END_ELEMENT;
01289 }
01290 }
01291
01292 void XMLStateReader::DefaultHandler(const std::string& s)
01293 {
01294 _content.append(EncodeXMLString(s));
01295
01296 assert(_state==XSS_NONE);
01297 _state = XSS_CHARACTERS;
01298 }
01299
01300 /*@@
01301 void XMLStateReader::XmlDeclHandler(const char* version, const char* encoding, int standalone)
01302 {
01303 _instructions.append("<?").append(_state_rdr.getPITarget())
01304 .append(" ").append(_state_rdr.getPIData()).append("?>");
01305 }
01306 */
01307
01308
01309 } // namespace XMLStorage