//+------------------------------------------------------------------+ //| XmlElement.mqh | //| yu-sha@ukr.net | //+------------------------------------------------------------------+ class CXmlAttribute; //----------------------------------------------------------------------------- // CXmlElement ! //----------------------------------------------------------------------------- class CXmlElement { private: string FName; CXmlAttribute *FAttributes[]; CXmlElement *FElements[]; string FText; CXmlElement *FParent; public: //--- constructor methods void CXmlElement(); void ~CXmlElement(); void Init( string aName, CXmlElement *aParent=NULL, string aText=""); void CopyTo(CXmlElement &aDst); virtual void Clear(); //--- main service methods string GetName() ; void SetName( string aName); string GetText() ; void SetText( string aText); CXmlElement *GetParent() ; void SetParent(CXmlElement *aParent); //--- attribute service methods int GetAttributeCount() ; int GetAttributeIndex(CXmlAttribute *aAttr) ; CXmlAttribute *GetAttribute( string aName) ; CXmlAttribute *GetAttribute(int aPos) ; string GetAttributeValue( string aName) ; CXmlAttribute *AttributeInsertAt(CXmlAttribute *aAttr,int aPos); CXmlAttribute *AttributeAdd(CXmlAttribute *aAttr); CXmlAttribute *AttributeInsertAfter(CXmlAttribute *aAfter,CXmlAttribute *aAttr); CXmlAttribute *AttributeInsertBefore(CXmlAttribute *aBefore,CXmlAttribute *aAttr); CXmlAttribute *AttributeRemove(CXmlAttribute *aAttr); CXmlAttribute *AttributeRemove(int aPos); void AttributeDelete(CXmlAttribute *aAttr); void AttributeDelete(int aPos); void AttributeDeleteAll(); //--- child service methods int GetChildCount() ; int GetChildIndex(CXmlElement *aElement) ; CXmlElement *GetChild( string aName) ; CXmlElement *GetChild(int aPos) ; string GetChildText( string aName) ; CXmlElement *ChildInsertAt(CXmlElement *aElement,int aPos); CXmlElement *ChildAdd(CXmlElement *aElement); CXmlElement *ChildInsertAfter(CXmlElement *aAfter,CXmlElement *aElement); CXmlElement *ChildInsertBefore(CXmlElement *aBefore,CXmlElement *aElement); CXmlElement *ChildRemove(CXmlElement *aElement); CXmlElement *ChildRemove(int aPos); void ChildDelete(CXmlElement *aElement); void ChildDelete(int aPos); void ChildDeleteAll(); string GetXml(int aLevel); bool InitByXmlText(string text, CXmlElement* xelement); void DoElementTrimText(CXmlElement &aXmlItem); }; //--------------------------------------------------------------------------------/ // CXmlElement :: implementation / //--------------------------------------------------------------------------------/ //+------------------------------------------------------------------+ //| Init from xml text | //+------------------------------------------------------------------+ bool CXmlElement::InitByXmlText(string text, CXmlElement* xelement) { CXmlElement FDocumentElement; 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++; string n = element.GetName(); xelement.SetName(n); // 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++; // init node CXmlAttribute* attr = new CXmlAttribute(); attr.SetName(attribute.GetName()); attr.SetValue(attribute.GetValue()); xelement.AttributeAdd(attr); } 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 return(false); } } while(p(aPos); --i) FAttributes[i]=FAttributes[i-1]; FAttributes[aPos]=aAttr; return aAttr; }; //+------------------------------------------------------------------+ //| AttributeAdd | //+------------------------------------------------------------------+ CXmlAttribute *CXmlElement::AttributeAdd(CXmlAttribute *aAttr) { return AttributeInsertAt(aAttr,GetAttributeCount()); }; //+------------------------------------------------------------------+ //| AttributeInsertAfter | //+------------------------------------------------------------------+ CXmlAttribute *CXmlElement::AttributeInsertAfter(CXmlAttribute *aAfter,CXmlAttribute *aAttr) { return AttributeInsertAt(aAttr,GetAttributeIndex(aAfter)+1); }; //+------------------------------------------------------------------+ //| AttributeInsertBefore | //+------------------------------------------------------------------+ CXmlAttribute *CXmlElement::AttributeInsertBefore(CXmlAttribute *aBefore,CXmlAttribute *aAttr) { return AttributeInsertAt(aAttr,GetAttributeIndex(aBefore)); }; //+------------------------------------------------------------------+ //| AttributeRemove | //+------------------------------------------------------------------+ CXmlAttribute *CXmlElement::AttributeRemove(CXmlAttribute *aAttr) { return AttributeRemove(GetAttributeIndex(aAttr)); }; //+------------------------------------------------------------------+ //| AttributeRemove | //+------------------------------------------------------------------+ CXmlAttribute *CXmlElement::AttributeRemove(int aPos) { CXmlAttribute *attr=FAttributes[aPos]; for(int i=aPos; i=0; i--) delete FAttributes[i]; ArrayResize(FAttributes,0); }; // Child service methods //+------------------------------------------------------------------+ //| GetChildCount | //+------------------------------------------------------------------+ int CXmlElement::GetChildCount() { return ArraySize(FElements); }; //+------------------------------------------------------------------+ //| GetChildIndex | //+------------------------------------------------------------------+ int CXmlElement::GetChildIndex(CXmlElement *aElement) { int i=0; while((i(aPos); --i) FElements[i]=FElements[i-1]; FElements[aPos]=aElement; aElement.SetParent(GetPointer(this)); return aElement; }; //+------------------------------------------------------------------+ //| ChildAdd | //+------------------------------------------------------------------+ CXmlElement *CXmlElement::ChildAdd(CXmlElement *aElement) { return ChildInsertAt(aElement,GetChildCount()); }; //+------------------------------------------------------------------+ //| ChildInsertAfter | //+------------------------------------------------------------------+ CXmlElement *CXmlElement::ChildInsertAfter(CXmlElement *aAfter,CXmlElement *aElement) { return ChildInsertAt(aElement,GetChildIndex(aAfter)+1); }; //+------------------------------------------------------------------+ //| ChildInsertBefore | //+------------------------------------------------------------------+ CXmlElement *CXmlElement::ChildInsertBefore(CXmlElement *aBefore,CXmlElement *aElement) { return ChildInsertAt(aElement,GetChildIndex(aBefore)); }; //+------------------------------------------------------------------+ //| ChildRemove | //+------------------------------------------------------------------+ CXmlElement *CXmlElement::ChildRemove(CXmlElement *aElement) { return ChildRemove(GetChildIndex(aElement)); }; //+------------------------------------------------------------------+ //| ChildRemove | //+------------------------------------------------------------------+ CXmlElement *CXmlElement::ChildRemove(int aPos) { //delete FElements[aPos]; //for(int i=aPos; i=0; i--) delete FElements[i]; ArrayResize(FElements,0); }; //+------------------------------------------------------------------+ //| GetXml | //+------------------------------------------------------------------+ string CXmlElement::GetXml(int aLevel) { string t="";; for(int i=0; i"); else { StringAdd(s,">"); for(int i=0; i0) && (FText!="")) StringAdd(s,"\r\n"); // StringAdd(s,TextPreProcess(FText)); StringAdd(s,FText); //FText="*"+FText+"*"; if((ArraySize(FElements)>0)) StringAdd(s,"\r\n"+t); StringAdd(s,""); } return(s); }; //+------------------------------------------------------------------+ //| TextPreProcess | //+------------------------------------------------------------------+ string TextPreProcess( string s) { // Заменить " & < > на "e, ... return(s); }; //+------------------------------------------------------------------+