Schau, wie man Roboter kostenlos herunterladen kann
Finden Sie uns auf Facebook!
und werden Sie Mitglied unserer Fangruppe
Interessantes Skript?
Veröffentliche einen Link auf das Skript, damit die anderen ihn auch nutzen können
Hat Ihnen das Skript gefallen?
Bewerten Sie es im Terminal MetaTrader 5
Bibliotheken

EasyXML - XML Parser - Bibliothek für den MetaTrader 5

Ansichten:
1202
Rating:
(54)
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:

  1. URL
  2. Dateieingabe
  3. 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

MethodeZweckReturn
 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

MethodeZweckReturn
 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

Lesen Sie für weitere Möglichkeiten der Arbeit mt Knoten und Kontenarray bitte die Dokumentation für CObject und CArrayObj.


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

JMASlope_HTF JMASlope_HTF

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

SlopeDirectionLine_HTF SlopeDirectionLine_HTF

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

FX_FISH_2MA FX_FISH_2MA

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

Vegas Vegas

Verschiedene Hüllkurven mit fixierter Verschiebung.