UTE/Strategy/XML/XmlElement.mqh
super.admin bd7e405a90 convert
2025-05-30 16:34:43 +02:00

705 lines
55 KiB
MQL5

//+------------------------------------------------------------------+
//| 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)=="<?xml";
if((StringSubstr(text,p,5)=="<?xml") && StringFind(WhiteSpace,StringSubstr(text,p+5,1))>=0)
{ // Prolog
p=StringFind(text,"?>",p+StringLen("<?xml"));
if(p<0)
{
err="Not find '?>' from position "+IntegerToString(p) + ".";
return(false);
}
p+=StringLen("?>");
}
else
if(StringSubstr(text,p,StringLen("<?"))=="<?")
{
// PI
}
else
if(StringSubstr(text,p,StringLen("<!--"))=="<!--")
{
// Comment
p=StringFind(text,"-->",p+StringLen("<!--"));
if(p<0)
{
err="Not find '-->' from position " + IntegerToString(p) + ".";
return(false);
}
p+=3;
}
else
if(StringSubstr(text,p,StringLen("<!DOCTYPE"))=="<!DOCTYPE")
{
// Dtdc
}
else
if(StringSubstr(text,p,StringLen("<![CDATA["))=="<![CDATA[")
{
// Cdata
p=StringFind(text,"]]>",p+StringLen("<![CDATA["));
if(p<0)
{
err="Not find ']]>' from position "+IntegerToString(p) + ".";
return(false);
}
p+=StringLen("]]>");
}
else
if(StringSubstr(text,p,StringLen("</"))=="</")
{
// End tag
p+=2;
string name="";
if(StringFind(NameStart,StringSubstr(text,p,1))<0)
{
err="Invalid character in position "+IntegerToString(p) + ".";
return(false);
}
StringAdd(name,StringSubstr(text,p++,1));
while(p<StringLen(text) && StringFind(NameChar,StringSubstr(text,p,1))>=0)
StringAdd(name,StringSubstr(text,p++,1));
while(p<StringLen(text) && StringFind(WhiteSpace,StringSubstr(text,p,1))>=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<StringLen(text) && StringFind(NameChar,StringSubstr(text,p,1))>=0)
element.SetName(element.GetName()+StringSubstr(text,p++,1));
while(p<StringLen(text) && StringFind(WhiteSpace,StringSubstr(text,p,1))>=0)
p++;
string n = element.GetName();
xelement.SetName(n);
// Attributes
while(p<StringLen(text) && StringSubstr(text,p,2)!="/>" && StringSubstr(text,p,1)!=">")
{
// Attribute's name
while(p<StringLen(text) && StringFind(WhiteSpace,StringSubstr(text,p,1))>=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<StringLen(text) && StringFind(NameChar,StringSubstr(text,p,1))>=0)
attribute.SetName(attribute.GetName()+StringSubstr(text,p++,1));
// =
while(p<StringLen(text) && StringFind(WhiteSpace,StringSubstr(text,p,1))>=0)
p++;
if(StringSubstr(text,p,1)!="=")
{
err="Substring " + (string)p + " not find";
return(false);
}
p++;
// Value
while(p<StringLen(text) && StringFind(WhiteSpace,StringSubstr(text,p,1))>=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<StringLen(text) && StringSubstr(text,p,1)!=quote)
attribute.SetValue(attribute.GetValue()+StringSubstr(text,p++,1));
p++;
while(p<StringLen(text) && StringFind(WhiteSpace,StringSubstr(text,p,1))>=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<StringLen(text) && StringFind(WhiteSpace,StringSubstr(text,p,1))>=0)
p++;
else
return(false);
}
}
while(p<StringLen(text));
DoElementTrimText(FDocumentElement);
return(true);
}
//+------------------------------------------------------------------+
//| DoElementTrimText |
//+------------------------------------------------------------------+
void CXmlElement::DoElementTrimText(CXmlElement &aXmlItem)
{
string s=aXmlItem.GetText();
StringTrimLeft(s);
StringTrimRight(s);
aXmlItem.SetText(s);
for(int i=0; i<aXmlItem.GetChildCount();++i)
DoElementTrimText(aXmlItem.GetChild(i));
}
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
void CXmlElement::CXmlElement()
{
FParent=NULL;
};
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
void CXmlElement::~CXmlElement()
{
Clear();
};
//+------------------------------------------------------------------+
//| Init |
//+------------------------------------------------------------------+
void CXmlElement::Init( string aName, CXmlElement *aParent=NULL, string aText="")
{
Clear();
SetName(aName);
SetParent(aParent);
SetText(aText);
};
//+------------------------------------------------------------------+
//| CopyTo |
//+------------------------------------------------------------------+
void CXmlElement::CopyTo(CXmlElement &aDst)
{
aDst.Clear();
aDst.FName = FName;
aDst.FText = FText;
aDst.FParent=NULL;
for(int i=0; i<ArraySize(FAttributes);++i)
aDst.AttributeAdd(FAttributes[i].Clone());
for(int i=0; i<ArraySize(FElements);++i)
{
CXmlElement *aItem=new CXmlElement;
FElements[i].CopyTo(aItem);
aDst.ChildAdd(aItem);
};
};
//+------------------------------------------------------------------+
//| Clear |
//+------------------------------------------------------------------+
void CXmlElement::Clear()
{
FName = "";
FText = "";
AttributeDeleteAll();
ChildDeleteAll();
};
// Main service methods
//+------------------------------------------------------------------+
//| GetName |
//+------------------------------------------------------------------+
string CXmlElement::GetName()
{
return FName;
};
//+------------------------------------------------------------------+
//| SetName |
//+------------------------------------------------------------------+
void CXmlElement::SetName( string aName)
{
FName=aName;
};
//+------------------------------------------------------------------+
//| GetText |
//+------------------------------------------------------------------+
string CXmlElement::GetText()
{
return FText;
};
//+------------------------------------------------------------------+
//| SetText |
//+------------------------------------------------------------------+
void CXmlElement::SetText( string aText)
{
FText=aText;
};
//+------------------------------------------------------------------+
//| GetParent |
//+------------------------------------------------------------------+
CXmlElement *CXmlElement::GetParent()
{
return FParent;
};
//+------------------------------------------------------------------+
//| SetParent |
//+------------------------------------------------------------------+
void CXmlElement::SetParent(CXmlElement *aParent)
{
FParent=aParent;
};
// Attribute service methods
//+------------------------------------------------------------------+
//| GetAttributeCount |
//+------------------------------------------------------------------+
int CXmlElement::GetAttributeCount()
{
return ArraySize(FAttributes);
};
//+------------------------------------------------------------------+
//| GetAttributeIndex |
//+------------------------------------------------------------------+
int CXmlElement::GetAttributeIndex(CXmlAttribute *aAttr)
{
int i=0;
while((i<ArraySize(FAttributes)) && (FAttributes[i]!=aAttr))
++i;
return(i<ArraySize(FAttributes) ? i : INT_MAX);
};
//+------------------------------------------------------------------+
//| GetAttribute |
//+------------------------------------------------------------------+
CXmlAttribute *CXmlElement::GetAttribute( string aName)
{
int i=0;
while((i<ArraySize(FAttributes)) && (aName!=FAttributes[i].GetName()))
++i;
if(i<ArraySize(FAttributes))
return FAttributes[i];
else
return NULL;
};
//+------------------------------------------------------------------+
//| GetAttribute |
//+------------------------------------------------------------------+
CXmlAttribute *CXmlElement::GetAttribute(int aPos)
{
return FAttributes[aPos];
};
//+------------------------------------------------------------------+
//| GetAttributeValue |
//+------------------------------------------------------------------+
string CXmlElement::GetAttributeValue( string aName)
{
int i=0;
while((i<ArraySize(FAttributes)) && (aName!=FAttributes[i].GetName()))
++i;
return(i<ArraySize(FAttributes) ? FAttributes[i].GetValue() : "");
};
//+------------------------------------------------------------------+
//| AttributeInsertAt |
//+------------------------------------------------------------------+
CXmlAttribute *CXmlElement::AttributeInsertAt(CXmlAttribute *aAttr,int aPos)
{
ArrayResize(FAttributes,ArraySize(FAttributes)+1);
for(int i=ArraySize(FAttributes)-1; i>(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<ArraySize(FAttributes)-1;++i)
FAttributes[i]=FAttributes[i+1];
ArrayResize(FAttributes,ArraySize(FAttributes)-1);
return attr;
};
//+------------------------------------------------------------------+
//| AttributeDelete |
//+------------------------------------------------------------------+
void CXmlElement::AttributeDelete(CXmlAttribute *aAttr)
{
delete AttributeRemove(aAttr);
};
//+------------------------------------------------------------------+
//| AttributeDelete |
//+------------------------------------------------------------------+
void CXmlElement::AttributeDelete(int aPos)
{
delete AttributeRemove(aPos);
};
//+------------------------------------------------------------------+
//| AttributeDeleteAll |
//+------------------------------------------------------------------+
void CXmlElement::AttributeDeleteAll()
{
for(int i=ArraySize(FAttributes)-1; 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<ArraySize(FElements)) && (FElements[i]!=aElement))
++i;
return(i<ArraySize(FElements) ? i : INT_MAX);
};
//+------------------------------------------------------------------+
//| GetChild |
//+------------------------------------------------------------------+
CXmlElement *CXmlElement::GetChild( string aName)
{
int i=0;
while((i<ArraySize(FElements)) && (aName!=FElements[i].GetName()))
++i;
if(i<ArraySize(FElements))
return FElements[i];
else
return NULL;
};
//+------------------------------------------------------------------+
//| GetChild |
//+------------------------------------------------------------------+
CXmlElement *CXmlElement::GetChild(int aPos)
{
return FElements[aPos];
};
//+------------------------------------------------------------------+
//| GetChildText |
//+------------------------------------------------------------------+
string CXmlElement::GetChildText( string aName)
{
CXmlElement *child=GetChild(aName);
return child!=NULL ? child.GetText() : "";
};
//+------------------------------------------------------------------+
//| ChildInsertAt |
//+------------------------------------------------------------------+
CXmlElement *CXmlElement::ChildInsertAt(CXmlElement *aElement,int aPos)
{
ArrayResize(FElements,ArraySize(FElements)+1);
for(int i=ArraySize(FElements)-1; 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<ArraySize(FElements)-1;++i)
// FElements[i]=FElements[i+1];
CXmlElement *child=FElements[aPos];
child.SetParent(NULL);
for(int i=aPos; i<ArraySize(FElements)-1;++i)
FElements[i]=FElements[i+1];
ArrayResize(FElements,ArraySize(FElements)-1);
return child;
};
//+------------------------------------------------------------------+
//| ChildDelete |
//+------------------------------------------------------------------+
void CXmlElement::ChildDelete(CXmlElement *aElement)
{
delete ChildRemove(aElement);
};
//+------------------------------------------------------------------+
//| ChildDelete |
//+------------------------------------------------------------------+
void CXmlElement::ChildDelete(int aPos)
{
delete ChildRemove(aPos);
};
//+------------------------------------------------------------------+
//| ChildDeleteAll |
//+------------------------------------------------------------------+
void CXmlElement::ChildDeleteAll()
{
for(int i=ArraySize(FElements)-1; i>=0; i--)
delete FElements[i];
ArrayResize(FElements,0);
};
//+------------------------------------------------------------------+
//| GetXml |
//+------------------------------------------------------------------+
string CXmlElement::GetXml(int aLevel)
{
string t="";;
for(int i=0; i<aLevel;++i)
t+="\t";
string s;
s=t+"<"+FName;
for(int i=0; i<ArraySize(FAttributes); i++)
StringAdd(s," "+FAttributes[i].GetName()+"=\""+TextPreProcess(FAttributes[i].GetValue())+"\"");
if((ArraySize(FElements)==0) && (FText==""))
StringAdd(s,"/>");
else
{
StringAdd(s,">");
for(int i=0; i<ArraySize(FElements); i++)
StringAdd(s,"\r\n"+FElements[i].GetXml(aLevel+1));
if((ArraySize(FElements)>0) && (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,"</"+FName+">");
}
return(s);
};
//+------------------------------------------------------------------+
//| TextPreProcess |
//+------------------------------------------------------------------+
string TextPreProcess( string s)
{
// Заменить " & < > на &quote, ...
return(s);
};
//+------------------------------------------------------------------+