//+------------------------------------------------------------------+ //| XmlDocument.mqh | //| yu-sha@ukr.net | //+------------------------------------------------------------------+ #include "XmlElement.mqh" //+------------------------------------------------------------------+ //| CXmlDocument | //+------------------------------------------------------------------+ class CXmlDocument { private: void DoElementTrimText(CXmlElement &aXmlItem); // /// Флаг, указывающий, что загрузка и сохранение файла происходит из общей деректории. /// int common; public: /// /// Читает из открытого файла содержимое Xml-документа. /// \param handle - Файловый дискриптор. /// \param err - Сообщение об ошибке. /// \return Истина, если запись прошла удачно и ложь в противном случае. /// bool ReadDocument(int handle, string& err); /// /// Записывает в начало открытого файла содержимое Xml-документа. /// \param handle - Файловый дискриптор. /// \param err - Сообщение об ошибке. /// \return Истина, если запись прошла удачно и ложь в противном случае. /// bool WriteDocument(int handle, string& err); CXmlElement FDocumentElement; void SetCommon(bool res){ common = res ? FILE_COMMON : 0;} void CXmlDocument(); void ~CXmlDocument(); void Clear(); void CopyTo(CXmlDocument &xmlDoc); bool CreateFromText( string &xml,string &err); bool CreateFromFile( string filename,string &err); bool SaveToFile( string filename); string GetXml(); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ void CXmlDocument::CXmlDocument() { common = FILE_COMMON; }; //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ void CXmlDocument::~CXmlDocument() { Clear(); }; //+------------------------------------------------------------------+ //| Clear | //+------------------------------------------------------------------+ void CXmlDocument::Clear() { /* if (DocumentElement!=NULL) { delete DocumentElement; DocumentElement=NULL; }*/ FDocumentElement.Clear(); }; //+------------------------------------------------------------------+ //| CopyTo | //+------------------------------------------------------------------+ void CXmlDocument::CopyTo(CXmlDocument &aDst) { aDst.Clear(); FDocumentElement.CopyTo(aDst.FDocumentElement); }; //+------------------------------------------------------------------+ //| CreateFromText | //+------------------------------------------------------------------+ bool CXmlDocument::CreateFromText( string &text,string &err) { /* В text приходит текст XML документа - переведенный в Юникод - очищенный от BOM заголовка UTF-8 */ // #define _PubidChar _WhiteSpace+_LatinLetter+_Digit+"\'" + "-()+,./:=?;!*#@$_%" // #define Utf8BOM "\xEF\xBB\xBF" string WhiteSpace = " \r\n\t"; string LatinLetter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; string ANSIILetter = "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF"; string Digit = "0123456789"; string QuoteChar = "\'\""; string Letter = LatinLetter + ANSIILetter; string NameChar = Letter + Digit + ".-_:\xB7"; string NameStart = Letter + "_:"; Clear(); int p=0; CXmlElement *CurElement=NULL; do { if(p>=StringLen(text)) { err="Unexpected end of document by position " + IntegerToString(p) + ". Check valid text or exits file."; return(false); } bool res = StringSubstr(text,p,5)=="=0) { // Prolog p=StringFind(text,"?>",p+StringLen("' from position "+IntegerToString(p) + "."; return(false); } p+=StringLen("?>"); } else if(StringSubstr(text,p,StringLen("",p+StringLen("' from position " + IntegerToString(p) + "."; return(false); } p+=3; } else if(StringSubstr(text,p,StringLen("",p+StringLen("' from position "+IntegerToString(p) + "."; return(false); } p+=StringLen("]]>"); } else if(StringSubstr(text,p,StringLen("=0) StringAdd(name,StringSubstr(text,p++,1)); while(p=0) p++; if(CurElement==NULL || CurElement.GetName()!=name || StringSubstr(text,p,1)!=">") { err="Invalid closing tag in position "+IntegerToString(p) + "."; return(false); } p++; if(CurElement==GetPointer(FDocumentElement)) CurElement=NULL; else { CXmlElement *parent=GetPointer(FDocumentElement); while(parent!=NULL && parent.GetChildCount()>0 && parent.GetChild(parent.GetChildCount()-1)!=CurElement) parent=parent.GetChild(parent.GetChildCount()-1); if(parent.GetChild(parent.GetChildCount()-1)!=CurElement) { err="Error in nested position "+IntegerToString(p) + "."; return(false); } CurElement=parent; }; } else if(StringSubstr(text,p,StringLen("<"))=="<") { // Start tag p++; CXmlElement *element=NULL; if(CurElement!=NULL) { element=new CXmlElement; CurElement.ChildAdd(element); } else { element=GetPointer(FDocumentElement); } // Tag name if(StringFind(NameStart,StringSubstr(text,p,1))<0) { err="Substring " + (string)p + " not find"; return(false); } element.SetName(element.GetName()+StringSubstr(text,p++,1)); while(p=0) element.SetName(element.GetName()+StringSubstr(text,p++,1)); while(p=0) p++; // Attributes while(p=0) p++; if(StringFind(NameStart,StringSubstr(text,p,1))<0) { err="Substring " + (string)p + " not find"; return(false); } CXmlAttribute *attribute=new CXmlAttribute; element.AttributeAdd(attribute); attribute.SetName(attribute.GetName()+StringSubstr(text,p++,1)); while(p=0) attribute.SetName(attribute.GetName()+StringSubstr(text,p++,1)); // = while(p=0) p++; if(StringSubstr(text,p,1)!="=") { err="Substring " + (string)p + " not find"; return(false); } p++; // Value while(p=0) p++; if(StringFind(QuoteChar,StringSubstr(text,p,1))<0) { err="Substring " + (string)p + " not find"; return(false); } string quote=StringSubstr(text,p++,1); while(p=0) p++; } if(StringSubstr(text,p,2)=="/>") p+=2; else if(StringSubstr(text,p,1)==">") { p++; CurElement=element; } else { err="Substring " + (string)p + " not find"; return(false); } } else { // Text if(CurElement!=NULL) CurElement.SetText(CurElement.GetText()+StringSubstr(text,p++,1)); else if(p=0) p++; else { err = "Unrecognized tag '" + StringSubstr(text, p, 5) + "...'"; return(false); } } } while(p