und werden Sie Mitglied unserer Fangruppe
Veröffentliche einen Link auf das Skript, damit die anderen ihn auch nutzen können
Bewerten Sie es im Terminal MetaTrader 5
- Ansichten:
- 1369
- Rating:
- Veröffentlicht:
- 2016.05.18 16:36
- Aktualisiert:
- 2016.11.22 07:34
-
Benötigen Sie einen Roboter oder Indikator, der auf diesem Code basiert? Bestellen Sie ihn im Freelance-Bereich Zum Freelance
Hautpaufgabe und Möglichkeiten
EasyXML ist ein einfacher aber trotzdem leistungsfähiger XML-Parser der XML von drei verschiedenen Quellen lesen und parsen kann:
- URL
- Dateieingabe
- String Eingabe
Er ist vollständig in nativem MQL5 geschrieben und beruht nur auf der nativen Windows "wininet.dll" um XML-Dokumente von einer URL zu beziehen.
EasyXML liest sowohl XML als auch XHTML mit (annähernd) unbeschränkter Knotentiefe, so lange das Dokument das Sie zu parsen versuchen wohlgeformt ist. Aber es validiert nicht das XML gegen eine DTD oder ein XSLT Stylesheet.
MQL5 Integration
EasyXML's Node Klassen werden vom nativen MQL5 CObject vererbt und Knoten werden im CArrayObj gespeichert.
Beim Abarbeiten des DOM Baumes können Knoten einfach verändert werden, indem sowohl die öffentlichen EasyXML Methoden als auch die nativen Funktionen von MQL5 verwendet werden, um Daten aus dem DOM zu beziehen und im DOM zu speichern.
URL Datei Caching und Debugging
Da man sich nicht immer auf RSS Feed Uptimes verlassen kann, kann EasyXML eine XML Cache-Datei des Feed speichern, sobald es ihn zum ersten Mal erfolgreich von der URL geladen hat. Der Anwender kann die Cache-Datei statt des Live-Feeds für das Parsing verwenden wenn der Feed aus irgendwelchen Gründen nicht erreichbar sein sollte.
Da XML und XHTML Dokumente dazu tendieren fehlerhaft zu sein hat EasyXML eine Debuggingoption. Obwohl es kein beschädigtes XML reparieren kann, wird es sicherlich hilfreich dabei sein herauszufinden, wo der Fehler liegt. Wenn es eingeschaltet wird, wird es detaillierte Informationen über die geparsten Knoten ausgeben.
Außerdem werden alle Fehler die auftreten immer verfolgt und angedruckt, unabhängig davon, ob das Debugging ein- oder ausgeschaltet ist.
Grundsätzliche Verwendung
Binden Sie einfach die Basisklasse in Ihre Skripten ein und sie sind bereit für die Verwendung:
//+------------------------------------------------------------------+ //| Includes | //+------------------------------------------------------------------+ #include <EasyXML\EasyXml.mqh>
Erzeugen Sie als erstes in Ihrem Skript eine Instanz der EasyXML Klasse. Dann stellen Sie das Debugging und/oder Datei-Caching ein und rufen eine der verfügbaren Methoden zum Laden des XML und Start des Parsens auf:
//+------------------------------------------------------------------+ //| Skript Programmstart Funktion | //+------------------------------------------------------------------+ void OnStart() { // Erzeuge Instanz der Klasse CEasyXml CEasyXml EasyXmlDocument; // Optional Debugging EasyXmlDocument.setDebugging(true); // Url Cache-Datei einstellen EasyXmlDocument.setUrlCacheFile("forexcalendar.xml"); // Methode 1: Lade XML von URL if(EasyXmlDocument.loadXmlFromUrl("http://www.forexfactory.com/ffcal_week_this.xml")) { readRecursive(EasyXmlDocument.getDocumentRoot()); } // Leeren des DOM EasyXmlDocument.Clear(); // Methode 2: Lade XML von String if(EasyXmlDocument.loadXmlFromString("<root><child attr='value'>content</child><sibling>siblingcontent</sibling></root>")) { readRecursive(EasyXmlDocument.getDocumentRoot()); } // Leeren des DOM EasyXmlDocument.Clear(); // Methode 3: Lade XML von Datei if(EasyXmlDocument.loadXmlFromFile("forexcalendar.xml")) { readRecursive(EasyXmlDocument.getDocumentRoot()); } }
Zu Demonstrationszwekcen werden alle drei Methoden gezeigt. Normalerweise werden sie nicht alle gleichzeitig brauchen obwohl es möglich ist den DOM-Baum dazwischen zu leeren und das Parsing erneut zu starten - sogar von einer anderen Quelle. Verwenden Sie einfach den Clear() Befehl um den geparsten DOM-Baum zu leeren. setDebugging() und setUrlCacheFile() sind optional und müssen nicht aufgerufen werden, wenn sie nicht gebraucht werden.
EasyXmlDocument.getDocumentRoot() gibt immer den Wurzelknoten des DOM-Baumes zurück. Alle Knoten einschließlich des Wurzelknotens sind vom Typ CEasyXmlNode, der seinerseits vom MQL5 CObject (wie zuvor erwähnt) abgeleitet wurde. Ab hier können sowohl alle Methoden von EasyXml wie auch von CArrayObj und CObject parallel verwendet werden, um den geparsten DOM-Baum abzuarbeiten.
Das folgende Beispiel zeigt die Implementierung von readRecursive(), der globalen Funktion die im letzten Codebeispiel aufgerufen wird:
//+------------------------------------------------------------------+ //| XML rekursiv lesen | //+------------------------------------------------------------------+ int readRecursive(CEasyXmlNode *ActualNode,int iNodeLevel=0) { // Ausgabevariable string sSpace; string sOutput; // Ausgabe für bessere Lesbarkeit einrücken StringInit(sSpace,iNodeLevel*4,StringGetCharacter(" ",0)); // Ausgabestring anhängen sOutput += sSpace + IntegerToString(iNodeLevel) + " - Node Name: '" + ActualNode.getName() + "'"; sOutput += (ActualNode.getValue()) ? " Value: '" + ActualNode.getValue() + "'" : ""; // durch AttributeNodes interieren for(int i=0; i<ActualNode.Attributes().Total(); i++) { CEasyXmlAttribute *Attribute=ActualNode.Attributes().At(i); sOutput+=" || Attribute "+IntegerToString(i+1)+": '"+Attribute.getName()+"' Value: '"+Attribute.getValue()+"'"; } Print(sOutput); // durch Kindknoten iterieren for(int j=0; j<ActualNode.Children().Total(); j++) { CEasyXmlNode *ChildNode=ActualNode.Children().At(j); readRecursive(ChildNode,iNodeLevel+1); } return(0); }
Rekursives Lesen von XML-Dokumenten hat große Vorteile über lineares Lesen obwohl es nicht für alle Anwendungen geeignet ist. Das Aufrufen von Attributes() auf einem Konten wird alle geparsten Attribute abfragen wohingegen Children() die Kindknoten des aktuellen Knotens einliest. Beide Methoden geben ein CArrayObj zurück das die Elemente enthält. Der Aufruf von Total() auf solche Objekte kann in for()-Schleifen verwendet werden, um über die Elemente zu iterieren. getName() und getValue() geben den aktuellen Inhalt zurück der im Knoten gespeichert ist.
Natürlich ist es möligch über alle Knoten linear zu iterieren:
//+------------------------------------------------------------------+ //| Skript Programmstart Funktion | //+------------------------------------------------------------------+ void OnStart() { // Erzeuge Objekt der Klasse CEasyXml CEasyXml EasyXmlDocument; // Debugging einstellen EasyXmlDocument.setDebugging(false); // Beispiel: Gesamten DOM-Baum linear durchgehen if(EasyXmlDocument.loadXmlFromUrl("http://www.forexfactory.com/ffcal_week_this.xml")) { CEasyXmlNode *RootNode=EasyXmlDocument.getDocumentRoot(); //iteriere durch den Wurzelknoten for(int i=0; i<RootNode.Children().Total(); i++) { CEasyXmlNode *ChildNode=RootNode.Children().At(i); Print(IntegerToString(i)+" "+ChildNode.getName()); //iteriere durch Kindknoten for(int j=0; j<ChildNode.Children().Total(); j++) { CEasyXmlNode *SubNode=ChildNode.Children().At(j); Print(IntegerToString(i)+"-"+IntegerToString(j)+" "+SubNode.getName()+" | "+SubNode.getValue()); } } } }
Die Iteration funktioniert wie im rekursiven Beispiel, abtgesehen davon, dass eine separate for()-Schleife für jeden einzelnen zu lesenden Knotenlevel aufgerufen werden muss.
Außerdem ist es möglich den DOM Schritt für Schritt durchzugehen und einzelne Elemente zu verändern falls nötig:
//+------------------------------------------------------------------+ //| Skript Programmstart Funktion | //+------------------------------------------------------------------+ void OnStart() { // Erzeuge Objekt der Klasse CEasyXml CEasyXml EasyXmlDocument; // Debugging einstellen EasyXmlDocument.setDebugging(true); // Beispiel 2: DOM-Baum Schritt für Schritt durchgehen if(EasyXmlDocument.loadXmlFromString("<root><child attr='value'>content</child><sibling>siblingcontent</sibling></root>")) { CEasyXmlNode *Node=EasyXmlDocument.getDocumentRoot(); Print(Node.getName()); CEasyXmlNode *ChildNode=Node.FirstChild(); Print(ChildNode.getName()); // Immer auf gültige Zeiger prüfen, wenn man manuell seitwärts geht. while(CheckPointer(ChildNode.Next())!=POINTER_INVALID) { ChildNode=ChildNode.Next(); Print(ChildNode.getName()); } CEasyXmlNode *ParentNode=ChildNode.Parent(); Print(ParentNode.getName()); // Zurück zur Wurzel: ParentNode und Node sind zwei verschiedene Deskriptoren des gleichen Objektes Print("Comparison of object descriptors: ParentNode == Node ? ",ParentNode==Node); } }
Hier kommen alle verfügbaren Methoden sowohl von EasyXML als auch die nativen MQL5 Iteration/Getter/Setter des CObject und CArrayObj ins Spiel.
Behalten Sie im Hinterkopf, dass einige dieser Funktionen sich nicht um gültigen Speicherzugriff kümmern und einfach NULL zurückgeben, wenn sie keinen Erfolg hatten.
Im letzten Beispiel würde der Aufruf von ChildNode.Next() auf einem Geschwisterknoten - ohne Prüfung der Zeigergültigkeit - eine bösen Zeigerfehler (= fehlerhafter Speicherzugriff) nach sich ziehen, der mit Sicherheit das Skript zum Absturz bringt. Wenn Sie also jemals manuell dem DOM-Baum durchgehen oder manipulieren müssen, kümmern Sie sich um die Zeigergültigkeit solange die CObject und CArrayObj Klassenmethoden betroffen sind.
Die wichtigsten Getters für Knoten
Methode | Zweck | Return |
---|---|---|
Chilrden() | Hole alle Kinder des Knoten | CArrayObj - enthält CEasyXmlNodes |
Attributes() | Hole alle Attribute des Knoten | CArrayObj - enthält CEasyXmlAttributes |
Parent() | Hole Elternknoten | CEasyXmlNode (CObject) |
LastChild() | Hole letzten Konten von den Kindern | CEasyXmlNode (CObject) |
FirstChild() | Hole ersten Knoten von den Kindern | CEasyXmlNode (CObject) |
getName() | Hole Knotenname | string |
getValue() | Hole Knotenwert (Textinhalt) | string |
getAttribute(string pName) | Hole das durch Name spezifizierte Attribute | string |
Next() (vererbt von CObject) | Hole den nächsten Geschwisterknoten | CEasyXmlNode (CObject) || NULL |
Prev() (vererbt von CObject) | Hole vorherigen Geschwisterknoten | CEasyXmlNode (CObject) || NULL |
Wichgiste Setters für Knoten
Methode | Zweck | Return |
---|---|---|
createChild(CEasyXmlNode *pChildNode) | Erzeugt einen neuen Kindknoten | CEasyXmlNode (CObject) - der neue Kindknoten |
createChild(CEasyXmlNode *pChildNode)createSibling(CEasyXmlNode *pSiblingNode) | Erzeuge neuen Geschwisterknoten | CEasyXmlNode (CObject) - der neue Geschwisterknoten |
setName(string pName) | Setze Knotenname | void |
setValue(string pValue) | Setze Knotenwert (Textinhalt) | void |
setAttribute(string pName,string pValue) | Setze neues Knotenattribut | void |
Attribut Getters/Setters
Attributobjekte implementieren die selben get/setName(), get/SetValue() Methoden zum Speichern und Auslesen von Daten wie die Knotenobjekte.
Haftungsausschluss
Dieses Stück Code wird aktiv entwickelt und wie bei aller Software, erhebt es keinen Anspruch auf Fehlerfreiheit oder Fehlen sonstiger Mängel. Verwenden Sie EasyXml auf eigenes Risiko und testen Sie es gründlich, bevor sie diese Bibliothek in irgendeinen live tradenden EA eingbauen. Wenn Sie irgendwelche Probleme oder Fragen bezüglich der Verwendung haben, wenden Sie sich bitte an mich.
Impressum
Die Integration von wininet.dll zum Abruf von URL Content verwendet WININET_TEST by Integer. Obwohl diese Bibliothek mit seinem eigenen Parsingsystem entwickelt wurde, war der XML Parser geschrieben von yu-sha eine hervorragende Informationsquelle für die Verwendung von Stringoperationen in MQL5.
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalpublikation: https://www.mql5.com/en/code/1998

Der JMASlope Indikator mit der Option TimeFrames in den Eingabeparametern auszuwählen.

Der SlopeDirectionLine Indikator mit der Option TimeFrames in den Eingabeparametern auszuwählen.

Fisher Transformation basierendes Histogramm mit zwei Durchschnitten in Form einer Signallinie.

Verschiedene Hüllkurven mit fixierter Verschiebung.