MyGUI 3.0.1
MyGUI_XmlDocument.cpp
Go to the documentation of this file.
00001 
00007 /*
00008     This file is part of MyGUI.
00009 
00010     MyGUI is free software: you can redistribute it and/or modify
00011     it under the terms of the GNU Lesser General Public License as published by
00012     the Free Software Foundation, either version 3 of the License, or
00013     (at your option) any later version.
00014 
00015     MyGUI is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018     GNU Lesser General Public License for more details.
00019 
00020     You should have received a copy of the GNU Lesser General Public License
00021     along with MyGUI.  If not, see <http://www.gnu.org/licenses/>.
00022 */
00023 #include "MyGUI_Precompiled.h"
00024 #include "MyGUI_XmlDocument.h"
00025 #include "MyGUI_DataManager.h"
00026 
00027 namespace MyGUI
00028 {
00029     namespace xml
00030     {
00031 
00032         namespace utility
00033         {
00034             std::string convert_from_xml(const std::string& _string, bool& _ok)
00035             {
00036                 std::string ret;
00037                 _ok = true;
00038 
00039                 size_t pos = _string.find("&");
00040                 if (pos == std::string::npos) return _string;
00041 
00042                 ret.reserve(_string.size());
00043                 size_t old = 0;
00044                 while (pos != std::string::npos)
00045                 {
00046                     ret += _string.substr(old, pos - old);
00047 
00048                     size_t end = _string.find(";", pos + 1);
00049                     if (end == std::string::npos)
00050                     {
00051                         _ok = false;
00052                         return ret;
00053                     }
00054                     else
00055                     {
00056                         std::string tag = _string.substr(pos, end - pos + 1);
00057                         if (tag == "&amp;") ret += '&';
00058                         else if (tag == "&lt;") ret += '<';
00059                         else if (tag == "&gt;") ret += '>';
00060                         else if (tag == "&apos;") ret += '\'';
00061                         else if (tag == "&quot;") ret += '\"';
00062                         else
00063                         {
00064                             _ok = false;
00065                             return ret;
00066                         }
00067                     }
00068 
00069                     old = end + 1;
00070                     pos = _string.find("&", old);
00071                 }
00072                 ret += _string.substr(old, std::string::npos);
00073 
00074                 return ret;
00075             }
00076 
00077             std::string convert_to_xml(const std::string& _string)
00078             {
00079                 std::string ret;
00080 
00081                 size_t pos = _string.find_first_of("&<>'\"");
00082                 if (pos == std::string::npos) return _string;
00083 
00084                 ret.reserve(_string.size() * 2);
00085                 size_t old = 0;
00086                 while (pos != std::string::npos)
00087                 {
00088                     ret += _string.substr(old, pos - old);
00089 
00090                     if (_string[pos] == '&') ret += "&amp;";
00091                     else if (_string[pos] == '<') ret += "&lt;";
00092                     else if (_string[pos] == '>') ret += "&gt;";
00093                     else if (_string[pos] == '\'') ret += "&apos;";
00094                     else if (_string[pos] == '\"') ret += "&quot;";
00095 
00096                     old = pos + 1;
00097                     pos = _string.find_first_of("&<>'\"", old);
00098                 }
00099                 ret += _string.substr(old, std::string::npos);
00100 
00101                 return ret;
00102             }
00103 
00104         }
00105 
00106         //----------------------------------------------------------------------//
00107         // class ElementEnumerator
00108         //----------------------------------------------------------------------//
00109         ElementEnumerator::ElementEnumerator(VectorElement::iterator _begin, VectorElement::iterator _end) :
00110             m_first(true),
00111             m_current(_begin),
00112             m_end(_end)
00113         {
00114         }
00115 
00116         bool ElementEnumerator::next()
00117         {
00118             if (m_current == m_end) return false;
00119             else if (m_first)
00120             {
00121                 m_first = false;
00122                 return true;
00123             }
00124             ++ m_current;
00125             if (m_current == m_end) return false;
00126             return true;
00127         }
00128 
00129         bool ElementEnumerator::next(const std::string& _name)
00130         {
00131             while (next())
00132             {
00133                 if ((*m_current)->getName() == _name) return true;
00134             }
00135             return false;
00136         }
00137 
00138         //----------------------------------------------------------------------//
00139         // class Element
00140         //----------------------------------------------------------------------//
00141         Element::Element(const std::string &_name, ElementPtr _parent, ElementType _type, const std::string& _content) :
00142             mName(_name),
00143             mContent(_content),
00144             mParent(_parent),
00145             mType(_type)
00146         {
00147         }
00148 
00149         Element::~Element()
00150         {
00151             for (VectorElement::iterator iter=mChilds.begin(); iter!=mChilds.end(); ++iter)
00152             {
00153                 delete *iter;
00154             }
00155             mChilds.clear();
00156         }
00157 
00158         void Element::save(std::ostream& _stream, size_t _level)
00159         {
00160             // сначала табуляции намутим
00161             for (size_t tab=0; tab<_level; ++tab) _stream  << "    ";
00162 
00163             // теперь заголовок тега
00164             if (mType == ElementType::Declaration) _stream << "<?";
00165             else _stream << "<";
00166             _stream << mName;
00167 
00168             for (VectorAttributes::iterator iter = mAttributes.begin(); iter != mAttributes.end(); ++iter)
00169             {
00170                 _stream << " " << iter->first << "=\"" << utility::convert_to_xml(iter->second) << "\"";
00171             }
00172 
00173             bool empty = mChilds.empty();
00174             // если детей нет то закрываем
00175             if (empty && mContent.empty())
00176             {
00177                 if (mType == ElementType::Declaration) _stream << "?>\n";
00178                 else _stream << "/>\n";
00179             }
00180             else
00181             {
00182                 _stream << ">";
00183                 if (!empty) _stream << "\n";
00184                 // если есть тело то сначало оно
00185                 if (!mContent.empty())
00186                 {
00187                     if (!empty)
00188                     {
00189                         for (size_t tab=0; tab<=_level; ++tab) _stream  << "    ";
00190                     }
00191                     _stream << utility::convert_to_xml(mContent);
00192 
00193                     if (!empty) _stream << "\n";
00194                 }
00195                 // если есть детишки путь сохранятся
00196                 for (size_t child=0; child<mChilds.size(); child++)
00197                 {
00198                     mChilds[child]->save(_stream, _level + 1);
00199                 }
00200 
00201                 if (!empty)
00202                 {
00203                     for (size_t tab=0; tab<_level; ++tab)
00204                         _stream  << "    ";
00205                 }
00206                 _stream << "</" << mName << ">\n";
00207             }
00208 
00209         }
00210 
00211         ElementPtr Element::createChild(const std::string& _name, const std::string& _content)
00212         {
00213             ElementPtr node = new Element(_name, this, ElementType::Normal, _content);
00214             mChilds.push_back(node);
00215             return node;
00216         }
00217 
00218         void Element::clear()
00219         {
00220             for (VectorElement::iterator iter = mChilds.begin(); iter != mChilds.end(); ++iter) delete *iter;
00221             mChilds.clear();
00222             mContent.clear();
00223             mAttributes.clear();
00224         }
00225 
00226         bool Element::findAttribute(const std::string& _name, std::string& _value)
00227         {
00228             for (VectorAttributes::iterator iter=mAttributes.begin(); iter!=mAttributes.end(); ++iter)
00229             {
00230                 if ( (*iter).first == _name)
00231                 {
00232                     _value = (*iter).second;
00233                     return true;
00234                 }
00235             }
00236             return false;
00237         }
00238 
00239         std::string Element::findAttribute(const std::string& _name)
00240         {
00241             for (VectorAttributes::iterator iter=mAttributes.begin(); iter!=mAttributes.end(); ++iter)
00242             {
00243                 if ( (*iter).first == _name) return (*iter).second;
00244             }
00245             return "";
00246         }
00247 
00248         void Element::addAttribute(const std::string& _key, const std::string& _value)
00249         {
00250             mAttributes.push_back(PairAttribute(_key, _value));
00251         }
00252 
00253         void Element::removeAttribute(const std::string& _key)
00254         {
00255             for (size_t index=0; index<mAttributes.size(); ++index)
00256             {
00257                 if (mAttributes[index].first == _key)
00258                 {
00259                     mAttributes.erase(mAttributes.begin() + index);
00260                     return;
00261                 }
00262             }
00263         }
00264 
00265         ElementPtr Element::createCopy()
00266         {
00267             Element* elem = new Element(mName, nullptr, mType, mContent);
00268             elem->mAttributes = mAttributes;
00269 
00270             for (VectorElement::iterator iter=mChilds.begin(); iter!=mChilds.end(); ++iter)
00271             {
00272                 Element* child = (*iter)->createCopy();
00273                 child->mParent = elem;
00274                 elem->mChilds.push_back(child);
00275             }
00276 
00277             return elem;
00278         }
00279 
00280         void Element::setAttribute(const std::string& _key, const std::string& _value)
00281         {
00282             for (size_t index=0; index<mAttributes.size(); ++index)
00283             {
00284                 if (mAttributes[index].first == _key)
00285                 {
00286                     mAttributes[index].second = _value;
00287                     return;
00288                 }
00289             }
00290             mAttributes.push_back(PairAttribute(_key, _value));
00291         }
00292 
00293         void Element::addContent(const std::string& _content)
00294         {
00295             if (mContent.empty()) mContent = _content;
00296             else
00297             {
00298                 mContent += " ";
00299                 mContent += _content;
00300             }
00301         }
00302 
00303 #if MYGUI_COMPILER == MYGUI_COMPILER_MSVC && !defined(STLPORT)
00304         inline void open_stream(std::ofstream& _stream, const std::wstring& _wide) { _stream.open(_wide.c_str()); }
00305         inline void open_stream(std::ifstream& _stream, const std::wstring& _wide) { _stream.open(_wide.c_str()); }
00306 #else
00307         inline void open_stream(std::ofstream& _stream, const std::wstring& _wide) { _stream.open(UString(_wide).asUTF8_c_str()); }
00308         inline void open_stream(std::ifstream& _stream, const std::wstring& _wide) { _stream.open(UString(_wide).asUTF8_c_str()); }
00309 #endif
00310 
00311         //----------------------------------------------------------------------//
00312         // class Document
00313         //----------------------------------------------------------------------//
00314         Document::Document():
00315             mRoot(0),
00316             mDeclaration(0),
00317             mLastErrorFile(""),
00318             mLine(0),
00319             mCol(0)
00320         {
00321         }
00322 
00323         Document::~Document()
00324         {
00325             clear();
00326         }
00327 
00328         // открывает обычным файлом, имя файла в utf8
00329         bool Document::open(const std::string& _filename)
00330         {
00331             std::ifstream stream;
00332             stream.open(_filename.c_str());
00333 
00334             if (!stream.is_open())
00335             {
00336                 mLastError = ErrorType::OpenFileFail;
00337                 setLastFileError(_filename);
00338                 return false;
00339             }
00340 
00341             bool result = open(stream);
00342 
00343             stream.close();
00344             return result;
00345         }
00346 
00347         // открывает обычным файлом, имя файла в utf16 или utf32
00348         bool Document::open(const std::wstring& _filename)
00349         {
00350             std::ifstream stream;
00351             open_stream(stream, _filename);
00352 
00353             if (!stream.is_open())
00354             {
00355                 mLastError = ErrorType::OpenFileFail;
00356                 setLastFileError(_filename);
00357                 return false;
00358             }
00359 
00360             bool result = open(stream);
00361 
00362             stream.close();
00363             return result;
00364         }
00365 
00366         bool Document::open(std::istream& _stream)
00367         {
00368             DataStream* data = new DataStream(&_stream);
00369 
00370             bool result = open(data);
00371             delete data;
00372 
00373             return result;
00374         }
00375 
00376         // сохраняет файл, имя файла в кодировке utf8
00377         bool Document::save(const std::string& _filename)
00378         {
00379             std::ofstream stream;
00380             stream.open(_filename.c_str());
00381 
00382             if (!stream.is_open())
00383             {
00384                 mLastError = ErrorType::CreateFileFail;
00385                 setLastFileError(_filename);
00386                 return false;
00387             }
00388 
00389             bool result = save(stream);
00390 
00391             if (!result)
00392             {
00393                 setLastFileError(_filename);
00394             }
00395 
00396             stream.close();
00397             return result;
00398         }
00399 
00400         // сохраняет файл, имя файла в кодировке utf16 или utf32
00401         bool Document::save(const std::wstring& _filename)
00402         {
00403             std::ofstream stream;
00404             open_stream(stream, _filename);
00405 
00406             if (!stream.is_open())
00407             {
00408                 mLastError = ErrorType::CreateFileFail;
00409                 setLastFileError(_filename);
00410                 return false;
00411             }
00412 
00413             bool result = save(stream);
00414 
00415             if (!result)
00416             {
00417                 setLastFileError(_filename);
00418             }
00419 
00420             stream.close();
00421             return result;
00422         }
00423 
00424         // открывает обычным потоком
00425         bool Document::open(IDataStream* _stream)
00426         {
00427             clear();
00428 
00429             // это текущая строка для разбора
00430             std::string line;
00431             // это строка из файла
00432             std::string read;
00433             // текущий узел для разбора
00434             ElementPtr currentNode = 0;
00435 
00436             while (!_stream->eof())
00437             {
00438                 // берем новую строку
00439                 _stream->readline(read, '\n');
00440                 if (read.empty()) continue;
00441                 if (read[read.size()-1] == '\r') read.erase(read.size()-1, 1);
00442                 if (read.empty()) continue;
00443 
00444                 mLine ++;
00445                 mCol = 0; // потом проверить на многострочных тэгах
00446                 if (read.empty()) continue;
00447                 // текущая строка для разбора и то что еще прочитали
00448                 line += read;
00449 
00450                 if (!parseLine(line, currentNode))
00451                 {
00452                     return false;
00453                 }
00454 
00455             } // while (!stream.eof())
00456 
00457             if (currentNode)
00458             {
00459                 mLastError = ErrorType::NotClosedElements;
00460                 return false;
00461             }
00462 
00463             return true;
00464         }
00465 
00466         bool Document::save(std::ostream& _stream)
00467         {
00468             if (!mDeclaration)
00469             {
00470                 mLastError = ErrorType::NoXMLDeclaration;
00471                 return false;
00472             }
00473 
00474             // заголовок utf8
00475             _stream << (char)0xEFu;
00476             _stream << (char)0xBBu;
00477             _stream << (char)0xBFu;
00478 
00479             mDeclaration->save(_stream, 0);
00480             if (mRoot) mRoot->save(_stream, 0);
00481 
00482             return true;
00483         }
00484 
00485         void Document::clear()
00486         {
00487             clearDeclaration();
00488             clearRoot();
00489             mLine = 0;
00490             mCol = 0;
00491         }
00492 
00493         bool Document::parseTag(ElementPtr &_currentNode, std::string _content)
00494         {
00495 
00496             // убераем лишнее
00497             MyGUI::utility::trim(_content);
00498 
00499             if (_content.empty())
00500             {
00501                 // создаем пустой тег
00502                 if (_currentNode) _currentNode = _currentNode->createChild("");
00503                 else
00504                 {
00505                     _currentNode = new Element("", 0);
00506                     // если это первый то запоминаем
00507                     if (!mRoot) mRoot = _currentNode;
00508                 }
00509                 return true;
00510             }
00511 
00512             char simbol = _content[0];
00513             bool tag_info = false;
00514 
00515             if (simbol == '!') return true; // проверяем на коментарии
00516 
00517             // проверяем на информационный тег
00518             if (simbol == '?')
00519             {
00520                 tag_info = true;
00521                 _content.erase(0, 1); // удаляем первый символ
00522             }
00523 
00524             size_t start, end;
00525             // проверяем на закрытие тега
00526             if (simbol == '/')
00527             {
00528                 if (_currentNode == 0)
00529                 {
00530                     // чета мы закрывам а ниче даже и не открыто
00531                     if (!mRoot)
00532                     {
00533                         mLastError = ErrorType::CloseNotOpenedElement;
00534                         return false;
00535                     }
00536                 }
00537                 // обрезаем имя тэга
00538                 start = _content.find_first_not_of(" \t", 1);
00539                 if (start == _content.npos)
00540                 {
00541                     // тег пустой
00542                     _content.clear();
00543                 }
00544                 else
00545                 {
00546                     end = _content.find_last_not_of(" \t");
00547                     _content = _content.substr(start, end - start+1);
00548                 }
00549                 // проверяем соответствие открывающего и закрывающего тегов
00550                 if (_currentNode->getName() != _content)
00551                 {
00552                     mLastError = ErrorType::InconsistentOpenCloseElements;
00553                     return false;
00554                 }
00555                 // а теперь снижаем текущий узел вниз
00556                 _currentNode = _currentNode->getParent();
00557             }
00558             else
00559             {
00560                 // выделяем имя до первого пробела или закрывающего тега
00561                 std::string cut = _content;
00562                 start = _content.find_first_of(" \t/?", 1); // << превед
00563                 if (start != _content.npos)
00564                 {
00565                     cut = _content.substr(0, start);
00566                     _content = _content.substr(start);
00567                 }
00568                 else
00569                 {
00570                     _content.clear();
00571                 }
00572 
00573                 if (_currentNode) _currentNode = _currentNode->createChild(cut);
00574                 else
00575                 {
00576                     if (tag_info)
00577                     {
00578                         // информационный тег
00579                         if (mDeclaration)
00580                         {
00581                             mLastError = ErrorType::MoreThanOneXMLDeclaration;
00582                             return false;
00583                         }
00584                         _currentNode = new Element(cut, 0, ElementType::Comment);
00585                         mDeclaration = _currentNode;
00586                     }
00587                     else
00588                     {
00589                         // рутовый тег
00590                         if (mRoot)
00591                         {
00592                             mLastError = ErrorType::MoreThanOneRootElement;
00593                             return false;
00594                         }
00595                         _currentNode = new Element(cut, 0, ElementType::Normal);
00596                         mRoot = _currentNode;
00597                     }
00598                 }
00599 
00600                 // проверим на пустоту
00601                 start = _content.find_last_not_of(" \t");
00602                 if (start == _content.npos) return true;
00603 
00604                 // сразу отделим закрывающийся тэг
00605                 bool close = false;
00606                 if ((_content[start] == '/') || (_content[start] == '?'))
00607                 {
00608                     close = true;
00609                     // не будем резать строку, просто поставим пробел
00610                     _content[start] = ' ';
00611                     // проверим на пустоту
00612                     start = _content.find_last_not_of(" \t");
00613                     if (start == _content.npos)
00614                     {
00615                         // возвращаем все назад и уходим
00616                         _currentNode = _currentNode->getParent();
00617                         return true;
00618                     }
00619                 }
00620 
00621                 // а вот здесь уже в цикле разбиваем на атрибуты
00622                 while (true)
00623                 {
00624                     // ищем равно
00625                     start = _content.find('=');
00626                     if (start == _content.npos)
00627                     {
00628                         mLastError = ErrorType::IncorrectAttribute;
00629                         return false;
00630                     }
00631                     // ищем вторые ковычки
00632                     end = _content.find_first_of("\"\'", start+1);
00633                     if (end == _content.npos)
00634                     {
00635                         mLastError = ErrorType::IncorrectAttribute;
00636                         return false;
00637                     }
00638                     end = _content.find_first_of("\"\'", end+1);
00639                     if (end == _content.npos)
00640                     {
00641                         mLastError = ErrorType::IncorrectAttribute;
00642                         return false;
00643                     }
00644 
00645                     std::string key = _content.substr(0, start);
00646                     std::string value = _content.substr(start+1, end-start);
00647 
00648                     // проверка на валидность
00649                     if (! checkPair(key, value))
00650                     {
00651                         mLastError = ErrorType::IncorrectAttribute;
00652                         return false;
00653                     }
00654 
00655                     // добавляем пару в узел
00656                     _currentNode->addAttribute(key, value);
00657 
00658                     // следующий кусок
00659                     _content = _content.substr(end+1);
00660 
00661                     // в строке не осталось символов
00662                     start = _content.find_first_not_of(" \t");
00663                     if (start == _content.npos) break;
00664 
00665                     mCol += start;
00666                 }
00667 
00668                 // был закрывающий тег для текущего тега
00669                 if (close)
00670                 {
00671                     // не проверяем имена, потому что это наш тэг
00672                     _currentNode = _currentNode->getParent();
00673                 }
00674 
00675             }
00676             return true;
00677         }
00678 
00679         bool Document::checkPair(std::string &_key, std::string &_value)
00680         {
00681             // в ключе не должно быть ковычек и пробелов
00682             MyGUI::utility::trim(_key);
00683             if (_key.empty()) return false;
00684             size_t start = _key.find_first_of(" \t\"\'&");
00685             if (start != _key.npos) return false;
00686 
00687             // в значении, ковычки по бокам
00688             MyGUI::utility::trim(_value);
00689             if (_value.size() < 2) return false;
00690             if (((_value[0] != '"') || (_value[_value.length()-1] != '"')) &&
00691                 ((_value[0] != '\'') || (_value[_value.length()-1] != '\''))) return false;
00692             bool ok = true;
00693             _value = utility::convert_from_xml(_value.substr(1, _value.length() - 2), ok);
00694             return ok;
00695         }
00696 
00697         // ищет символ без учета ковычек
00698         size_t Document::find(const std::string& _text, char _char, size_t _start)
00699         {
00700             // ковычки
00701             bool kov = false;
00702 
00703             // буфер для поиска
00704             char buff[16] = "\"_\0";
00705             buff[1] = _char;
00706 
00707             size_t pos = _start;
00708 
00709             while (true)
00710             {
00711                 pos = _text.find_first_of(buff, pos);
00712 
00713                 // если уже конец, то досвидания
00714                 if (pos == _text.npos) break;
00715 
00716                 // нашли ковычку
00717                 else if (_text[pos] == '"')
00718                 {
00719                     kov = !kov;
00720                     pos ++;
00721                 }
00722                 // если мы в ковычках, то идем дальше
00723                 else if (kov) pos ++;
00724 
00725                 // мы не в ковычках
00726                 else break;
00727 
00728             }
00729 
00730             return pos;
00731         }
00732 
00733         void Document::clearDeclaration()
00734         {
00735             if (mDeclaration)
00736             {
00737                 delete mDeclaration;
00738                 mDeclaration = 0;
00739             }
00740         }
00741 
00742         void Document::clearRoot()
00743         {
00744             if (mRoot)
00745             {
00746                 delete mRoot;
00747                 mRoot = 0;
00748             }
00749         }
00750 
00751         ElementPtr Document::createDeclaration(const std::string& _version, const std::string& _encoding)
00752         {
00753             clearDeclaration();
00754             mDeclaration = new Element("xml", 0, ElementType::Declaration);
00755             mDeclaration->addAttribute("version", _version);
00756             mDeclaration->addAttribute("encoding", _encoding);
00757             return mDeclaration;
00758         }
00759 
00760         ElementPtr Document::createRoot(const std::string& _name)
00761         {
00762             clearRoot();
00763             mRoot = new Element(_name, 0, ElementType::Normal);
00764             return mRoot;
00765         }
00766 
00767         bool Document::parseLine(std::string& _line, ElementPtr& _element)
00768         {
00769             // крутимся пока в строке есть теги
00770             while (true)
00771             {
00772                 // сначала ищем по угловым скобкам
00773                 size_t start = find(_line, '<');
00774                 if (start == _line.npos) break;
00775                 size_t end = _line.npos;
00776 
00777                 // пытаемся вырезать многострочный коментарий
00778                 if ((start + 3 < _line.size()) && (_line[start + 1] == '!') && (_line[start + 2] == '-') && (_line[start + 3] == '-'))
00779                 {
00780                     end = _line.find("-->", start + 4);
00781                     if (end == _line.npos) break;
00782                     end += 2;
00783                 }
00784                 else
00785                 {
00786                     end = find(_line, '>', start+1);
00787                     if (end == _line.npos) break;
00788                 }
00789                 // проверяем на наличее тела
00790                 size_t body = _line.find_first_not_of(" \t<");
00791                 if (body < start)
00792                 {
00793                     std::string body_str = _line.substr(0, start);
00794                     // текущий символ
00795                     mCol = 0;
00796 
00797                     if (_element != 0)
00798                     {
00799                         bool ok = true;
00800                         _element->setContent(utility::convert_from_xml(body_str, ok));
00801                         if (!ok)
00802                         {
00803                             mLastError = ErrorType::IncorrectContent;
00804                             return false;
00805                         }
00806                     }
00807                 }
00808                 // вырезаем наш тэг и парсим
00809                 if (!parseTag(_element, _line.substr(start+1, end-start-1)))
00810                 {
00811                     return false;
00812                 }
00813                 // и обрезаем текущую строку разбора
00814                 _line = _line.substr(end+1);
00815             }
00816             return true;
00817         }
00818 
00819         std::string Document::getLastError()
00820         {
00821             const std::string& error = mLastError.print();
00822             if (error.empty()) return error;
00823             return MyGUI::utility::toString("'", error, "' ,  file='", mLastErrorFile, "' ,  line=", mLine, " ,  col=", mCol);
00824         }
00825 
00826         /*Document Document::createCopyFromElement(ElementPtr _node)
00827         {
00828             Document doc;
00829             doc.mRoot = _node->createCopy();
00830             return doc;
00831         }*/
00832 
00833     } // namespace xml
00834 
00835 } // namespace MyGUI