Смотри, как бесплатно скачать роботов

Интересный скрипт?
Поставь на него ссылку - пусть другие тоже оценят

Понравился скрипт?
Оцени его работу в терминале MetaTrader 5

Библиотеки

EasyXML - XML Parser - библиотека для MetaTrader 5

Paul van Hemmen | Russian English 中文 Español Deutsch 日本語 Português

Просмотров:
3038
Рейтинг:
голосов: 48
Опубликован:
2013.12.25 16:38
Обновлен:
2016.11.22 07:33

Предназначение и возможности

EasyXML - это простой, но мощный парсер XML-документов, который может читать и обрабатывать XML-документы из трех различных источников:

  1. URL
  2. Файл
  3. Строка

EasyXML полностью написана на MQL5, библиотека Windows "wininet.dll" используется только для работы с URL-источниками данных.

Библиотека EasyXML позволяет работать как с XML, так и XHTML с бесконечной (теоретически) глубиной узла при условии корректности формирования обрабатываемого документа. Тем не менее, она не производит проверку корректности XML на соответствие DTD или XSLT.


Интеграция с MQL5

Класс узла CEasyXmlNode порожден от объекта CObject, узлы хранятся массивах указателей CArrayObj.

При проходе по DOM-дереву, получении значений и заполнении его данными, с его узлами можно работать как при помощи публичных методов класса EasyXML, так и с помощью функций языка MQL5.


Кэширование данных и опция отладки

Поскольку не всегда можно полагаться на отказоустойчивость RSS-каналов (RSS Feed), EasyXML может хранить кэшированный файл успешно загруженного RSS-канала. После этого пользователь может работать с кэшированном файлом, даже если RSS-канал по какой-либо причине стал недоступен.

Поскольку документы XML и XHTML бывают с ошибками, EasyXML имеет опцию отладки. Хотя с ее помощью нельзя восстановить некорректный XML, она поможет обнаружить место ошибки. При включенной опции отладки выводится детальная информация обо всех обработанных узлах.

Кроме того, информация о любых появившихся ошибках будет выводиться вне зависимости от статуса опции отладки.


Простой пример использования

Подключите базовый класс в вашу программу:

//+------------------------------------------------------------------+
//| Подключение библиотеки                                           |
//+------------------------------------------------------------------+
#include <EasyXML\EasyXml.mqh>

Сначала создайте экземпляр класса EasyXML. Затем нужно указать режим отладки и/или URL адрес кэшируемого файла, вызвать один из методов загрузки XML-документа и начать разбор:

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   //--- создаем экземпляр класса CEasyXml
   CEasyXml EasyXmlDocument;

   //--- включаем опцию отладки
   EasyXmlDocument.setDebugging(true);

   //--- устанавливаем URL кэшированного файла
   EasyXmlDocument.setUrlCacheFile("forexcalendar.xml");

   //--- метод 1: загрузка XML-документа из URL
   if(EasyXmlDocument.loadXmlFromUrl("http://www.forexfactory.com/ffcal_week_this.xml"))
     {
      readRecursive(EasyXmlDocument.getDocumentRoot());
     }

   //--- очистка дерева документа (DOM)
   EasyXmlDocument.Clear();

   //--- метод 2: загрузка XML-документа из строки
   if(EasyXmlDocument.loadXmlFromString("<root><child attr='value'>content</child><sibling>siblingcontent</sibling></root>"))
     {
      readRecursive(EasyXmlDocument.getDocumentRoot());
     }

   //--- очистка дерева документа (DOM)
   EasyXmlDocument.Clear();

   //--- метод 3: загрузка XML-документа из файла
   if(EasyXmlDocument.loadXmlFromFile("forexcalendar.xml"))
     {
      readRecursive(EasyXmlDocument.getDocumentRoot());
     }
  }

В качестве демонстрации приведены все три метода. Вряд-ли они понадобятся все сразу, хотя между их вызовами можно очищать DOM-дерево и снова производить анализ, даже из другого источника. Для очистки полученного DOM-дерева нужно просто вызвать метод Clear(). Методы setDebugging() и setUrlCacheFile() не являются обязательными.

Метод EasyXmlDocument.getDocumentRoot() всегда возвращает корневой узел (root node) DOM-дерева. Все дочерние узлы корневого узла имеют тип CEasyXmlNode, который порожден от класса CObject (как указывалось ранее). С этого момента все методы EasyXml (а также методы классов CArrayObj и CObject) могут использоваться для прохода по дереву документа.

Приведенный ниже пример иллюстрирует реализацию метода readRecursive() - глобальной функции, которая вызывалась в последнем примере.

//+------------------------------------------------------------------+
//| Рекурсивное чтение XML-документа                                 |
//+------------------------------------------------------------------+
int readRecursive(CEasyXmlNode *ActualNode,int iNodeLevel=0)
  {
   //--- выходные переменные
   string sSpace;
   string sOutput;

   //--- формирование отступа для лучшей читаемости
   StringInit(sSpace,iNodeLevel*4,StringGetCharacter(" ",0));

   //--- объединение выходной строки
   sOutput += sSpace + IntegerToString(iNodeLevel) + " - Node Name: '" + ActualNode.getName() + "'";
   sOutput += (ActualNode.getValue()) ? " Value: '" + ActualNode.getValue() + "'" : "";

   //--- проход по атрибутам узлов
   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);

   //--- проход по дочерним узлам
   for(int j=0; j<ActualNode.Children().Total(); j++)
     {
      CEasyXmlNode *ChildNode=ActualNode.Children().At(j);
      readRecursive(ChildNode,iNodeLevel+1);
     }

   return(0);
  }

Рекурсивное чтение XML-документов имеет преимущества перед построчным чтением, но не во всех случаях.

Вызов метода Attributes() узла выдаст все его атрибуты, в то время как вызов метода Children() выдаст его дочерние узлы. Оба метода возвращают ссылку на экземпляр класса CArrayObj, содержащий запрашиваемые элементы. Вызов метода Total() этих объектов может быть использован для перебора элементов в цикле for. Методы getName() и getValue() возвращают актуальное содержимое узла.

Разумеется, по всем узлам можно проходить последовательно:

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- создаем объект класса CEasyXml
   CEasyXml EasyXmlDocument;

//--- выключаем опцию отладки
   EasyXmlDocument.setDebugging(false);

//--- пример: прохождение по элементам DOM-дерева
   if(EasyXmlDocument.loadXmlFromUrl("http://www.forexfactory.com/ffcal_week_this.xml"))
     {
      CEasyXmlNode *RootNode=EasyXmlDocument.getDocumentRoot();

      //--- цикл прохода по дочерним узлам корневого узла
      for(int i=0; i<RootNode.Children().Total(); i++)
        {
         CEasyXmlNode *ChildNode=RootNode.Children().At(i);
         Print(IntegerToString(i)+" "+ChildNode.getName());

         //--- цикл прохода по дочерним узлам
         for(int j=0; j<ChildNode.Children().Total(); j++)
           {
            CEasyXmlNode *SubNode=ChildNode.Children().At(j);
            Print(IntegerToString(i)+"-"+IntegerToString(j)+"   "+SubNode.getName()+" | "+SubNode.getValue());
           }
        }
     }
  }

Цикл прохода по узлам аналогичен рекурсивному примеру, за исключением того, что для каждого узла каждого уровня используется отдельный цикл.

Кроме того, также можно пошагово пройтись по DOM и при необходимости обрабатывать отдельно каждый из элементов:

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- создаем объект класса CEasyXml
   CEasyXml EasyXmlDocument;

//--- включаем опцию отладки
   EasyXmlDocument.setDebugging(true);

//--- пример 2: пошаговый проход по DOM-дереву
   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());

      //--- в таких случаях всегда следует проверять корректность указателей
      while(CheckPointer(ChildNode.Next())!=POINTER_INVALID)
        {
         ChildNode=ChildNode.Next();
         Print(ChildNode.getName());
        }

      CEasyXmlNode *ParentNode=ChildNode.Parent();
      Print(ParentNode.getName());

      //--- возвращение обратно к корневому узлу: ParentNode и Node являются двумя разными дескрипторами одного объекта
      Print("Comparison of object descriptors: ParentNode == Node ? ",ParentNode==Node);
     }
  }

В этом примере используются все доступные методы EasyXML, а также методы чтения/установки значений классов CObject и CArrayObj.

Следует помнить о том, что некоторые из этих функций не проверяют корректность доступа к памяти, и в случае ошибки просто возвращают NULL.

В последнем примере вызов ChildNode.Next() соседнего (sibling) узла производится без проверки корректности указателя, это может привести к серьезной ошибке доступа к памяти и аварийному завершению скрипта.  Так что если у вас когда-нибудь возникнет необходимость ручной обработки DOM-дерева, следует заботиться о корректности указателей при работе при помощи методов классов CObject и CArrayObj.


Наиболее важные методы получения свойств (get-методы)

МетодПредназначениеВозвращаемое значение
 Chilrden() Получение всех дочерних узлов (Get all children of node) CArrayObj - содержит CEasyXmlNodes
 Attributes() Получение всех атрибутов узла (Get all attributes of node) CArrayObj - содержит CEasyXmlAttributes
 Parent() Получение родительского узла (Get parent node) CEasyXmlNode (CObject)
 LastChild()  Получение последнего дочернего узла (Get last node from children) CEasyXmlNode (CObject)
 FirstChild() Получение первого дочернего узла (Get first node from children) CEasyXmlNode (CObject)
 getName()  Получение имени узла (Get node name) string
 getValue() Получение значения - текстового содержимого узла (Get node value) string
 getAttribute(string pName)  Получение атрибута (Get Attribute by specified name) string
 Next() (унаследован от CObject)  Получение следующего узла (Get next sibling node) CEasyXmlNode (CObject) || NULL
 Prev() (унаследован от CObject)  Получение предыдущего узла (Get previous sibling node) CEasyXmlNode (CObject) || NULL

 

Наиболее важные методы установки свойств (set-методы)

МетодПредназначениеВозвращаемое значение
 createChild(CEasyXmlNode *pChildNode) Создание нового дочернего узла (Create new child node) CEasyXmlNode (CObject) - новый дочерний узел (new child node)
 createSibling(CEasyXmlNode *pSiblingNode) Создание нового соседнего узла (Create new sibling node) CEasyXmlNode (CObject) - новый соседний узел (new sibling node)
 setName(string pName)  Установка имени узла (Set node name) void
 setValue(string pValue) Установка значения узла (Set node value - text content) void
 setAttribute(string pName,string pValue)  Установка нового атрибута узла (Set new node attribute) void

Другие возможности работы с узлами и массивами узлов описаны в документации по классам CObject и CArrayObj.



Методы чтения/установки атрибутов

Атрибуты объектов содержат ту же реализацию методов getName()/setName(), getValue()/SetValue() чтения/установки значений, что и методы объектов-узлов.


Disclaimer

Данный код все еще в разработке, как и все программное обеспечение, он может содержать ошибки. Используйте его на свой страх и риск и тщательно протестируйте при использовании в любом торговом советнике. Если у вас возникнут какие-либо вопросы по его использованию, свяжитесь со мной.


Credits

Для работы с wininet.dll был использован WININET_TEST, предложенный Integer. Хотя в библиотеке используется собственный парсер, большую помощь как источник знаний по работе со строками в MQL5 оказал XML Parser, написанный yu-sha.

Перевод с английского произведен MetaQuotes Software Corp.
Оригинальная публикация: https://www.mql5.com/en/code/1998

BackgroundСandle_BrainTrend1_HTF BackgroundСandle_BrainTrend1_HTF

Индикатор, рисующий свечи прямоугольниками с более крупного таймфрейма в соответствии с показаниями индикатора BrainTrend1.

FisherCyberCycle_HTF FisherCyberCycle_HTF

Индикатор FisherCyberCycle с возможностью изменения таймфрейма индикатора во входных параметрах.

T3_TRIX T3_TRIX

Индикатор TRIX с использованием усреднения Тильсона.

BackgroundСandle_BrainTrend2_HTF BackgroundСandle_BrainTrend2_HTF

Индикатор, рисующий свечи прямоугольниками с более крупного таймфрейма в соответствии с показаниями индикатора BrainTrend2.