Як працювати з Json програмою ZennoPoster

Аббревіатура JSON – це скорочення від англійських слів JavaScript Object Notation, тобто опис об’єктів в мові програмування JavaScript. Проте, опис об’єктів у цьому форматі получився настільки зручним, що його зараз використовують майже завжди, у випадках коли потрібно передати чи відправити кудись дані.

Щоб працювати з JSON у програмі ZennoPoster потрібно спочатку розібратись з тим, як саме описуються дані у цьому форматі. Нам може зустрітись текст який починається вусатою дужкою, і закінчується вусатою дужкою – це опис об’єкта. Всередині об’єкта можна зустріти поля у подвійних кавичках після яких іде двокрапка і значення. Поля розділені між собою комами. Також може зустрітись текст, який починається квадратною дужкою, і закінчується квадратною дужкою – це опис масиву. Масиви можуть находитись в якості значення поля об’єкта, або весь JSON текст може бути масивом. Всередині масивів находяться об’єкти, інші масиви і рядки. Елементи розділяються комами. Текстові рядки обрамлені просто подвійними кавичками. Зазвичай рядки знаходяться всередині масивів.
Більш детально з JSON можна ознайомитись у ВікіПедії.

Так от, щоб звертатись до об’єктів чи елементів масиву, які находяться в JSON, його потрібно десеріалізувати, тобто привести до такого об’єкта, з яким вміє працювати мова програмування на якій пишеться код. ZennoPoster дозволяє працювати використовуючи мову C#. Для роботи з JSON у C# є декілька способів, і один із них використання бібліотеки NewtonSoft.Json. Ця бібліотека використовується всередині ZennoPoster, тому встановлювати її додатково немає необхідності. Находиться вона у просторі імен Global.ZennoLab.Json. Говорю я про це тому, що ніхто спеціально не запам’ятовує всі специфічні команди для роботи з JSON. Коли є якась не стандартна ситуація, то потрібно просто піти на сайт розробників і прочитати необхідний розділ документації.

Коли в нас є JSON, він зберігається у текстовій змінній. Щоб його десеріалізувати і працювати з ним використовуючи макроси ZennoPoster у інших блоках використовується така операція:

project.Json.FromString(json);

Проте, коли у нас у перемінній буде текст не в форматі JSON, то результатом виконання буде помилка.
Інколи щоб уникнути такої поведінки, можна одіти інструкцію в блок try/catch

try {  project.Json.FromString(json); } catch {return json; }

Може бути також протележна ситуація, коли у нас уже є десеріалізований JSON, який знаходиться у project.Json, і нам необхідно одержати JSON у вигляді текстового рядка. Тоді використовується інструкція:

return project.Json.ToString();

Проте, не завжди зручно користуватись саме таким способом, тому що в результаті такої десеріалізації у нас в об’єкті project.Json тип даних буде dynamic, який не завжди вказує на той тип, який може знадобитись. Тому, випадках, коли я знаю, що одержав об’єкт JSON – я використовую інструкцію:

var dic = Global.ZennoLab.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(json);

Це дає можливість мені звертатись до полів по імені ключів словника:

return dic["field"];

Якщо я знаю що на вхід мені прийшов JSON масив – тоді я десеріалізую його у список словників такою інструкцією:

var list_dic = Global.ZennoLab.Json.JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(json);

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

foreach(var dic in list_dic){
project.SendInfoToLog(string.Format("{0}", dic["field"]));
}

Потрібно звернути увагу, що я в якості значеннь для словника вказую тип object, тому що там може бути як звичайний об’єкт, так і масив. Тому, у випадках, коли я знаю, що у мене якесь конкретне значення поля має тип даних масив – я просто серіалізую цей об’єкт в текстовий рядок, і наступною командою десеріалізую уже в потрібний мені тип даних словник чи список чи список словників.

foreach(var dic in list_dic){
string item1 = Global.ZennoLab.Json.JsonConvert.SerializeObject(dic["field_1"]);
var dic_item = Global.ZennoLab.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(item1);

string item2 = Global.ZennoLab.Json.JsonConvert.SerializeObject(dic["field_2"]);
var array_item  = Global.ZennoLab.Json.JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(item2);

}

На цьому прикладі добре видно, чому не використовується стандартний project.Json.FromString – так як зразу після десеріалізації іншого текстового рядка – дані всередині project.Json зміняться, а значить перебрати всі значення за допомогою циклу не получиться.

Також, на цьому прикладі видно як можна серіалізувати будь-який об’єкт у текстовий рядок JSON, який наприклад можна добавити у список і вже відпрацьовувати у декілька потоків ZennoPoster.

JSON може бути у сформований у вигляді одного рядка, а може бути відформатованим для зручності перегляду людиною. Для цього у серіалізатор можна подати відповідні параметри:

return Global.ZennoLab.Json.JsonConvert.SerializeObject(ob,  Global.ZennoLab.Json.Formatting.Indented); // з форматуванням
return Global.ZennoLab.Json.JsonConvert.SerializeObject(ob,  Global.ZennoLab.Json.Formatting.None); // в один рядок

І тут також виявляється що зручніше використовувати цю інструкцію, ніж project.Json.ToString(), так як в ньому немає можливості змінити форматування результату в потрібному вигляді.

Використовувати JSON у програмі ZennoPoster зручно також для того, щоб наприклад подивитись значення всіх змінних профіля, чи значеннь будь-яких об’єктів, не думаючи як саме їх потрібно приводити до текстового рядка (вивід в лог у ZennoPoster на відміну від Console.WriteLine приймає виключно текстові рядки).

Корисно також знати, що є можливість змінити налаштування серіалізації за змовчуванням на свої налаштування. Наприклад зазвичай при серіалізації поля які містять значення null можуть виключатись, і щоб добавляти їх, можна використовувати приблизно такі інструкції:

var settings = new Global.ZennoLab.Json.JsonSerializerSettings();
settings.NullValueHandling = Global.ZennoLab.Json.NullValueHandling.Include;
return Global.ZennoLab.Json.JsonConvert.SerializeObject(ob, settings: settings );

У мові C# об’єкти передаються по посиланні. Це означає, що коли ми створили об’єкт, потім присвоїли його іншому об’єкту, після чого у початковому об’єкті змінили наприклад значення поля – то в іншому об’єкті також значення буде змінене. Для того, щоб змінити таку поведінку можна серіалізувати об’єкт у JSON, а потім десеріалізувати JSON у новий об’єкт. В результаті у нас буде дві незалежні копії об’єкта, у кожного об’єкта свої дані, зміна яких у одному об’єкті не буде впливати на інший об’єкт.

Інколи розробники замість того, щоб сформувати словник з даними і серіалізувати його у JSON лінуються, і беруть готовий текстовий рядок, в якому у необхідні поля пробують підставляти значення із змінних. Проте у такому випадку вони упускають один момент – всередині значення змінної можуть бути різні символи, наприклад символ двійної кавички. В результаті відправивши кудись таким чином сформований JSON сервер не зможе програмно його десеріалізувати і буде видавати помилку (а розробнику важко буде зрозуміти в чому саме проблема). Тому рекомендую завжди коли є необхідність працювати з JSON формувати його структуру з об’єктів методом серіалізації – це однозначно допоможе уникнути подібних проблем, які буває важко визначити.

А для того, щоб завжди не писати багато символьні інструкції, буває зручно створити статичний клас, у якому добавити методи розширення, наприклад ToJson і FromJson – це може полегшити і пришвидшити роботу.

Надіюсь вам сподобається працювати з даними, описаними в форматі JSON.

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *