Json в mql: JAson
23 марта 2021 г. 1:32
В MQL нет возможности хранить данные различных типов через стандартные типы данных, как это можно сделать в python через словари или в javascript через объекты. Так как MQL типизированный язык, то реализация данных в виде словаря, где хранятся данные в виде пар "ключ - значение", весьма трудоёмко. К счастью, есть замечательная библиотека JAson, которая позволяет хранить данные различных типов в виде словаря, а если быть точнее, то в виде JSON. Также библиотека преобразовывать JSON объект в виде строки и обратно.
Код библиотеки можно найти на странице mql5.com/ru/code/13663. Так как библиотека не находится в каком-либо репозитории, то во-первых, сложно следить за обновлениями, а во-вторых, произвести автоматизацию по обновлению этой библиотеки у себя на рабочей машине, поэтому я выложил её к себе в репозиторий, добавив документацию (которой изначально особо не было), юнит-тесты и небольшие исправления.
Библиотека JAson находится на github по ссылке:
https://github.com/vivazzi/JAson
Установка
Скачайте (склонируйте) репозиторий и скопируйте JAson/Include/JAson.mqh
в папку <TERMINAL DIR>/MQL(4/5)/Include
.
Использование
Добавьте #include <JAson.mqh>
и создайте CJAVal
объект для работы с JSON. Для быстрого понимания посмотрите этот пример:
#include <JAson.mqh> int OnInit(){ CJAVal data; // --- simple structure --- data["a"] = 12; data["b"] = 3.14; data["b"] = "foo"; data["d"] = true; Print(data["a"].ToInt()); // 12 Print(data["b"].ToDbl()); // 3.14 Print(data["c"].ToStr()); // "foo" Print(data["d"].ToBool()); // true // --- array structure --- data["e"].Add("bar"); data["e"].Add(2); Print(data["e"][0].ToStr()); // "bar" Print(data["e"][1].ToInt()); // 2 // --- nested structures --- // - as part of array - CJAVal sub_data_obj_in_list; sub_data_obj_in_list["k1"] = 7; sub_data_obj_in_list["k2"] = "baz"; data["e"].Add(sub_data_obj_in_list); Print(data["e"][2]["k1"].ToInt()); // 7 Print(data["e"][2]["k2"].ToStr()); // "baz" // - as object - CJAVal sub_data_obj; sub_data_obj["sub_c"] = "muz2"; sub_data_obj["sub_d"] = 44; data["f"].Set(sub_data_obj); Print(data["f"]["sub_c"].ToStr()); // "muz2" Print(data["f"]["sub_d"].ToInt()); // 44 }
Внимание: чтобы присвоить другой CJAVal
объект к текущему по какому-то ключу, используйте метод Set()
вместо прямого присваивания через знак =
, иначе текущий CJAVal
объект не сохранить ключ, а точнее сохранит вложенные данные с пустым ключом.
Подробнее в тикете: https://github.com/vivazzi/JAson/issues/1
Для получения значения из CJAVal
объекта используйте методы:
ToInt()
дляinteger
ToDbl()
дляdouble
ToStr()
дляstring
ToBool()
дляboolean
Например:
data["a"].ToInt(); // 12 data["b"].ToDbl(); // 3.14 data["c"].ToStr(); // "foo" data["d"].ToBool(); // true
Для создания массива используйте .Add()
:
data["e"].Add("bar"); data["e"].Add(2);
Для использования вложенного json, создайте другой CJAVal объект и присвуйте к существующему CJAVal объекту. Вложенный CJAVal объект может быть значением ключа или содержаться в массиве:
CJAVal data; // - adding as object - CJAVal data_1; data_1["d1_1"] = 7; data_1["d1_2"] = "foo"; data["a"].Set(data_1); // - adding as part of array - CJAVal data_2; data_2["d2_1"] = 1; data_2["d2_1"] = "bar"; data["b"].Add("buz"); data["b"].Add(data_2); data["b"].Add("muz");
Сериализация и десериализация
JAson обеспечивает сериализацию и десериализацию:
#include <JAson.mqh> int OnInit(){ string data_str; CJAVal data; data["a"] = 3.14; data["b"] = "foo"; data["c"].Add("bar"); data["c"].Add(2); data["c"].Add("baz"); Print(data["b"].ToStr()); // foo data_str = data.Serialize(); Print(data_str); // {"a":3.14000000,"b":"foo","c":["bar",2,"baz"]} CJAVal data_2; data_2.Deserialize(data_str); Print(data_2["a"].ToDbl()); // 3.14 Print(data_2["b"].ToStr()); // foo Print(data_2["c"][0].ToStr()); // bar Print(data_2["c"][1].ToInt()); // 2 Print(data_2["c"][2].ToStr()); // baz }
Это может быть полезно для сохранения данных в файл, например, для хранения исторических данных или взаимодействия между терминалами или экспертами. Также это может быть полезно для взаимодействия с интернет ресурсами.
Пример: POST запрос с Json:
#include <JAson.mqh> #include <requests/requests.mqh> // https://github.com/vivazzi/mql_requests int OnInit(){ CJAVal data; data["a"] = 7; data["b"] = "foo"; Requests requests; Response response = requests.post("https://vivazzi.pro/test-request/", data.Serialize()); Print(response.text); // {"status": "OK", "method": "POST", "body": "{"a": 7, "b": "foo"}"} data.Deserialize(response.text); Print(data["status"].ToStr()); // "OK" Print(data["method"].ToStr()); // "POST" Print(data["body"].ToStr()); // {"a": 7, "b": "foo"} // if Json object has value of key as serialized object, you can also deserialize this value CJAVal data_2; data_2.Deserialize(data["body"].ToStr()); Print(data_2["a"].ToInt()); // 7 Print(data_2["b"].ToStr()); // "foo" // also you can join this Json objects to get full structure data["body"].Set(data_2); Print(data["body"]["a"].ToInt()); Print(data["body"]["b"].ToStr()); }
В этом примере была использована библиотека mql_requests и Getest - сервис для тестирования запросов.
Clear Json and check for the existence of a key
Для очистки CJAVal
объекта, используйте метод Clear()
:
#include <JAson.mqh> int OnInit(){ CJAVal data; string data_str; data["a"] = 3.14; data["b"] = "foo"; data_str = data.Serialize(); Print(data_str); // "{"a":3.14000000,"b":"foo"}" data.Clear(); data["c"] = 123; data["d"] = "bar"; data_str = data.Serialize(); Print(data_str); // "{"c":123,"d":"bar"}" }
Таким образом, получить значения ключей "c" и "d" можно так:
Print(data["c"].ToInt()) // 123 Print(data["d"].ToStr()) // "bar"
Но если проверить ключи "a" и "b", которые больше не существуют, или проверить никогда не использованные ключи, то вы получите значения по умолчанию:
// old notexistent keys Print(data["a"].ToDbl()) // 0.0 Print(data["b"].ToStr()) // "" (empty) // never used keys Print(data["e"].ToStr()) // "" (empty)
И это может привести к логическим ошибкам - будьте осторожны! Всегда используйте определённый набор ключей, чтобы избечать логических ошибок!
Если вы используйтете JSON, который может быть очищен, или используете различные ключи, вы можете проверить тип ключа. JAson библиотека определяет следующие типы ключей:
jtUNDEF
, если ключ не определёнjtNULL
дляNULL
jtBOOL
дляboolean
jtINT
дляint
jtDBL
дляdouble
jtSTR
дляstring
jtARRAY
дляarray
jtOB
дляobj
Тогда в примере выше можно опредлить типы:
// old notexistent keys Print(data["a"].ToDbl()); // 0.0 Print(data["a"].m_type); // jtUNDEF Print(data["b"].ToStr()); // "" Print(data["b"].m_type); // jtUNDEF // current keys Print(data["c"].ToInt()); // 123 Print(data["c"].m_type); // jtINT Print(data["d"].ToStr()); // "bar" Print(data["d"].m_type); // jtSTR // never used keys Print(data["e"].ToStr()); // "" Print(data["e"].m_type); // jtUNDEF
Таким образом, вы можете сравнивать тип ключа с jtUNDEF, чтобы проверить существование ключа:
#include <JAson.mqh> int OnInit(){ CJAVal data; data["a"] = 3.14; data.Clear(); data["c"] = 123; if (data["a"].m_type == jtUNDEF) { // do something } else { // else do something } }
API
CJAVal data;
- Создаёт CJAVal
(Json) объект
data[key] = some_val;
- Добавляет some_val
(int, double, string) в data
с ключём key
data[key].Add(other_data);
- Добавляет other_data
(int, double, string или другой CJAVal
) к ключу массива
data[key].Set(other_data);
- Присваивает other_data
CJAVal
объект к data
объекту с определённым ключём key
data.Clear();
- Очищает CJAVal
объект
data.Size();
- Возвращает размер CJAVal
объекта
Библиотека JAson находится на github по ссылке:
https://github.com/vivazzi/JAson
Представляю вашему вниманию книгу, написанную моим близким другом Максимом Макуриным: Секреты эффективного управления ассортиментом.
Книга предназначается для широкого круга читателей и, по мнению автора, будет полезна специалистам отдела закупок и логистики, категорийным и финансовым менеджерам, менеджерам по продажам, аналитикам, руководителям и директорам, в компетенции которых принятие решений по управлению ассортиментом.
Комментарии: 0