Ранее, мы рассмотрели формат CSV. Для получения информации из любой ячейки при помощи iMacros и Javascript там используется конструкция, вроде такой — tableData[1][2]
. С одной стороны это удобно, но в больших таблицах с кучей столбцов можно легко запутаться под каким индексом находятся необходимые данные. Это проблему решает другой формат и называется он — JSON.
Структура формата JSON
JSON(JavaScript Object Notation) — простой формат обмена данными, удобный для чтения и написания как человеком, так и компьютером. Он используется для представления объектов в виде строки и это самый удобный формат данных для взаимодействия с Javascript. В браузерах есть множество замечательных методов, знание тонкостей которых делает операции с JSON простыми и удобными.
Данные в формате JSON могут состоять из:
- JavaScript-объекты
{ ... }
или - Массивы
[ ... ]
или - Значения одного из типов:
- строки в двойных кавычках,
- число,
- логическое значение
true
/false
, null
.
Давайте возьмем структуру данных из прошлого урока и сделаем из нее JS-объект, который потом можно будет преобразовать в валидный JSON:
Старая структура для CSV:
var arr = [ [1,"John Smith",1961], [2,"Mike Trump",1975], [3,"Oliver Stone",1982] ];
Новая структура для JSON:
var obj = { title: "Citizens", peoples: [ { order: 1, name: "John Smith", year: 1961 }, { order: 2, name: "Mike Trump", year: 1975 }, { order: 3, name: "Oliver Stone", year: 1982 } ] };
Может показаться, что кода стало больше и становится не совсем ясно, к чему такие преобразования. На самом деле, у такого массива может быть бесконечная вложенность с полноценной иерархией, что в табличной структуре невозможно. К тому же, мы можем обращаться к элементам такого массива по именному ключу, например:
obj.title // "Citizens" obj.peoples[0].name // "John Smith" obj.peoples[1]["year"] // 1975
Это действительно очень удобно и мы можем создавать по-настоящему гибкие массивы и совершать над ними любые манипуляции.
В Javascript два основных метода для работы с JSON — это преобразование строки в Javascript Object и обратное преобразование объекта в строку.
Метод JSON.parse() — превращаем строку в JS-объект
Чаще всего этот метод используется, когда мы с сервера делаем запрос и получаем обычную строку с текстом в формате JSON. Мы не можем сразу обращаться к ключам и значениям объектов в этой строке. Javascript интерпретатор пока что воспринимает эту строку, как строку и не знает, что на самом деле, там содержатся разные объекты. Поэтому, необходимо сначала преобразовать эту строку в Javascript-объект, чтобы дальше можно было работать с ней, как с объектом.
Для этого и существует метод JSON.parse()
.
Примеры:
// Массив чисел var nums = '[555, 666, 777]'; window.console.log(nums[0]); // "[" - первый символ строки nums = JSON.parse(nums); // преобразование в обычный массив window.console.log(nums[0]); // 555 - первый элемент массива // Наш прошлый объект var obj = '{"title": "Citizens","peoples": [{"order": 1,"name": "John Smith","year": 1961},{"order": 2,"name": "Mike Trump","year": 1975},{"order": 3,"name": "Oliver Stone","year": 1982}]}'; window.console.log(obj.title); //undefined obj = JSON.parse(obj); // преобразование в обычный объект window.console.log(obj.title); // Citizens
Примечание: Обратите внимание, ключи(например «title») в объекте я обернул двойными кавычками. Для ключей одинарные кавычки являются ошибкой. Еще в формате JSON не поддерживаются комментарии, для их поддержки есть специальный формат JSON5.
В качестве второго параметра метод JSON.parse() может принимать функцию-реплейсер, которая позволяет на этапе преобразования восстанавливать строку более гибким образом.
Пример со вторым аргументом JSON.parse(text, replacer):
// Дата в строке - в формате UTC var str = '{"title":"My Birthday","date":"1952-01-20T12:00:00.000Z"}'; var calendar = JSON.parse(str); // "getDate()" - это встроенный метод объекта "new Date()" window.console.log( calendar.date.getDate() ); // Ошибка undefined var calendar = JSON.parse(str, function(key, value) { if (key == 'date') {return new Date(value);} return value; }); window.console.log( calendar.date.getDate() ); // 20 - день месяца
Учтите, что эта функция рекурсивная и она проходит абсолютно по каждому значению вашего объекта, независимо от вложенности. Лично я, редко использую данную возможность, но иногда она бывает очень к месту.
Метод JSON.stringify() — превращаем JS-объект в строку
Как вы уже догадались, это функция для обратного преобразования объекта в строку. Учтите, что если в вашем объекте попадется функция — она не будет преобразована и высока вероятность возникновения ошибки.
Пример простого преобразования:
var str = { title: "My Birthday", date: new Date("1952-01-20") }; str = JSON.stringify(str); window.console.log( str ); // {"title":"My Birthday","date":"1952-01-20T00:00:00.000Z"}
Обратите внимание, наш объект Date превратился в строку в формате UTC, это произошло потому, что у него есть встроенный метод toJSON
. Проверьте сами в FireBug при помощи автокомплита.
Исключение свойств, функция replacer
В качестве второго параметра вы можете указать список свойств, которые нужно преобразовать в строку.
Например:
var str = { title: "My Birthday", date: new Date("1952-01-20"), window: window, age: 15 }; window.console.log( JSON.stringify(str, ["title", "date"]) ); // {"title":"My Birthday","date":"1952-01-20T00:00:00.000Z"}}
Тут я добавил в наш объект 2 новых свойства, которые были проигнорированы при преобразовании в строку, поскольку не были добавлены, как разрешенные.
Также метод JSON.stringify()
поддерживает в качестве параметра функцию-реплейсер и работает аналогично методу JSON.parse()
.
Пример с аргументом функции:
var str = { title: "My Birthday", date: new Date("1952-01-20"), window: window, age: 15 }; var str = JSON.stringify(str, function(key, value) { if (key == 'window' || key == 'age') return undefined; return value; }); window.console.log( str ); // {"title":"My Birthday","date":"1952-01-20T00:00:00.000Z"}
Добавляем красоты и отступов при форматировании
Помимо первых двух параметров, у метода JSON.stringify()
есть и третий, который отвечает за количество отступов перед каждым ключом. Измеряется отступ в количестве пробелов.
var str = { title: "My Birthday", date: new Date("1952-01-20") }; window.console.log( JSON.stringify(str) ); // {"title":"My Birthday","date":"1952-01-20T00:00:00.000Z"} window.console.log( JSON.stringify(str, "", 4) ); /* { "title": "My Birthday", "date": "1952-01-20T00:00:00.000Z" } */
Создаем свой метод для чтения и записи JSON
В очередной раз мы воспользуемся функциями для чтения и записи файлов из прошлых уроков, но добавим еще и преобразование объекта в JSON и наоборот. Еще, будет уместно добавить обработку ошибок, например, если вы открываете некорректный JSON. Подобные ошибки могу привести к остановке работы iMacros.
Сохранение объекта в JSON
// Функция для сохранения массива в файл в формате JSON var saveToJSON = function (fileName, obj) { try { var fileDescriptor = imns.FIO.openNode(fileName); imns.FIO.writeTextFile( fileDescriptor, JSON.stringify(obj, null, 4) ); } catch (e) { return e; } return true; }; // Тестовый объект var obj = { title: "My Birthday", date: new Date("1952-01-20"), window: window }; // Сохраняем в формате JSON var cb = saveToJSON("C:\\BOTS\\iMacros\\test.json", obj); // Проверяем корректно ли сохранилось if (cb == true) { window.console.log('Сохранено успешно!'); } else { window.console.log('Ошибка сохранения'); window.console.log(cb); }
Чтение из JSON и преобразование в объект Javascript
// Функция для сохранения массива в файл в формате JSON var readFromJSON = function (fileName) { try { var fileDescriptor = imns.FIO.openNode(fileName); var text = imns.FIO.readTextFile(fileDescriptor); var obj = JSON.parse(text); return obj; } catch (e) { return false; } }; // Читаем из формата JSON var cb = readFromJSON("C:\\BOTS\\iMacros\\test.json"); // Если открылось правильно - увидим распарсенный объект, иначе - false window.console.log(cb);
Таким нехитрым образом можно сохранять и считывать огромные массивы данных.
Если все наши небольшие, но удобные функции собрать в один большой объект, может получиться отличнейшая библиотека для работы с iMacros+Javascript, которая сэкономит кучу времени на различных рутинных операциях и добавит потрясающие возможности вашим ботам. Вы сможете подключать такую библиотеку в начало каждого вашего скрипта и использовать весь функционал, который мы рассмотрели за все это время.
Я потихоньку уже начал работать над такой библиотекой и в скором времени она перерастет в отдельный проект со своей подробной документацией и коммьюнити.
Есть возможность кликнуть по flash контенту?
Спасибо, весьма познавательно!
Хочу еще спросить, возможно ли сделать, что бы json файл обновлялся при каждом запуске скрипта?
То есть, при первом запуске создается структура [] и добавляется объект. При всех последующих запусках скрипта, просто дописываются объекты с разделителем ‘,’ через appendTextFile например
Ден, конечно можно!
Только
appendTextFile
тут не подойдет, поскольку нам нужно дописывать не совсем в конец файла.Вам необходимо считать файл в формате
JSON
, преобразовать его вjavascript-объект
, при помощи методаpush
вы можете добавить новый объект в массив, после чего преобразуете массив в строку и сохраняете в файл.P.S. не забудьте добавить в код функции
saveToJSON
иreadFromJSON
из урока, чтобы код ниже заработал.Пример кода:
Решил эту задачу через создание массива и запись туда старого и нового объекта через .concat и последующую перезапись в json файл. Но ваш вариант на порядок лучше. Спасибо!
приветствую! у меня почему то не до записывает в файл а удаляет запись и делает её по новой, а как сделать что бы он просто до записывал от последнего файла?
Разобрался вроде. стало до записывать но есть нюанс. нужно убрать из кода это строчку var obj = {
title: «Citizens»,
peoples: [
{
order: 1,
name: «John Smith»,
year: 1961
}
]
};
но если файл будет пустой то не запишет ничего. Поэтому нужно создать файл с одной записью потом удалит тот когд и оставить только вторую часть
var cb = readFromJSON(«C:\\BOTS\\iMacros\\test.json»);
// Добавляем в массив еще один объект
cb.push({
order: 2,
name: «Mike Trump»,
year: 1975
});
// Сохраняем в JSON массив уже с двумя объектами
saveToJSON(«C:\\BOTS\\iMacros\\test.json», cb);
Давно читаю ваши статьи, спасибо за качественный контент. Также хотел спросить почему вы не объявляете функцию напрямую, а даете значение переменной. Так ведь нужно писать переменные в начале скрипта, что в принципе не критично, но ведь объявление функции сразу же ставит её в глобальную область видимости и в будущем, при расширении функционала, никогда не возникнет проблем. Это никак не высер в вашу сторону, просто интересно.
Скажите пожалуйста, если пришел ответ вида:
{«status»:»SUCCESS»,»link»:»http://vk.com/wall-12345_67890″}
как из него вырезать или извлечь ссылку и перейти по ней?
Не корректно отобразилось предыдущее сообщение, вот такого вида ответ:
{«status»:»SUCCESS»,»link»:»http://vk.com/wall-12345_67890″}
«Ошибка сохранения» jsplayer.js:200:1
TypeError: cyclic object value
Стек-трейс:
saveToJSON@chrome://imacros/content/jsplayer.js:178:43
@chrome://imacros/content/jsplayer.js:195:10
JS_Player.prototype.play@chrome://imacros/content/jsplayer.js:172:13
obj.playJSFile@chrome://imacros/content/iMacros.js:961:13
obj.play@chrome://imacros/content/iMacros.js:642:13
oncommand@chrome://imacros/content/iMacrosSidebar.xul:1:1
Везде подвохи 🙂 разобрался
Написали бы в чем подвох….((
Я его еще не нашел..
подвох в 20й строчке:
было: window: window
надо: window: «window»