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