Очень часто при написании скриптов мы сталкиваемся с использованием формата JSON
и регулярно наши клиенты спрашивают как работать с JSON в скриптах
Human Emulator.

В связи с этим мы решили написать вводную статью на эту тему.

Работа с JSON в скриптах XHE полностью аналогична работе с JSON в PHP. Более подробно про
работу с JSON вы можете найти в разделе «литература».

JSON (JavaScript Object Notation) — текстовый формат обмена данных, основанный
на подмножестве JavaScript.

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

Несмотря на происхождение от JavaScript (точнее, от подмножества языка стандарта
1999-го г.), формат считается языконезависимым и может использоваться практически
с любым языком программирования (в т.ч., PHP имеет встроенную поддержку JSON)
json php

За счёт своей лаконичности по сравнению с XML, формат JSON может быть более
подходящим для сериализации сложных структур.

Например, если говорить о веб-приложениях, то JSON уместен в задачах обмена данными
между браузером и сервером, а так же, между серверами.
Если говорить о десктопных приложениях, то JSON можно использовать для хранения
конфигурационных файлов программы.

JSON — текст представляет собой (в закодированном виде) одну из двух структур:
* Набор пар «ключ: значение». В PHP это реализовано как ассоциативный массив (array).
Ключом может быть строка, а значением — любой поддерживаемый тип.

	{
		"key1": "value for key1",
		"key2": 2,
		"key3": [
			"value 1 for key3",
			2,
			"the 3"
		]
	}

Упорядоченный набор значений. В PHP это реализовано как простой массив (array).

      [
          "one",
          2,
          {
             "key1": 1
          }
      ]

Базовые типы JSON:

* «Число» — десятичное число (не делает никакого различия между целыми и числами
с плавающей точкой). Не поддерживается NaN (не-число, Not A Number).

* «Строка» — упорядоченное множество из нуля или более символов юникода, заключённое в
двойные кавычки.

* «Булев» (boolean) — значения либо true, либо false.

* «Массив» — упорядоченнное множество значений, каждое из которых может быть
любого поддерживаемого типа. Массив заключается в квадратные скобки «[]».
Значения разделяются запятыми.

* «Объект» — неупорядоченное множество пар «ключ: значение», заключённое в фигурные
скобки «{}». «Ключ» описывается «строкой», между ним и значением стоит символ «:».
Пары «ключ-значение» отделяются друг от друга запятыми.

* «null» — пустое значение означающее «ничего».

JSON не поддерживает и не разрешает любой вид комментариев, но комментарии
можно эмулировать, например, создав объект с ключом «comment» и в
значении вписать комментарий.

Следующий пример показывает JSON-представление объекта, описывающего человека.
В объекте есть строковые поля имени и фамилии, объект, описывающий адрес,
и массив, содержащий список телефонов:

  {
    "comment": "пример эмуляции комментария в JSON",
  
    "first_name": "Иван",
    "last_name": "Иванов",
    "age": 31,
    "address": {
      "street_address": "Московское ш., 101, кв. 101",
      "city": "Москва",
      "postal_code": "123456"
    },
    "phones": [
      "+7 978 123 45 67",
      "+7 978 123 45 68"
    ]
  }

Предположим, у нас стоит задача вытянуть какие-то данные из веб-сайта и
сохранить их в виде JSON. Для примера, спарсим данные компаний занимающихся
фрахтовкой яхт с сайта yellowpagesrussia.ru
(только первую страницу).

Наш JSON будет следующего формата:

[
    {
      "name": "название фирмы",
      "address": "физический адрес офиса",
      "tel": "телефон",
    },
    { и т.д. ... },
    { и т.п. ... }
  ]

Алгоритм работы нашего скрипта будет такой:

1. открываем страницу сайта

2. получаем информацию со страницы (строку)

3. сконвертируем (используя разделитель «\r\n \r\n») полученную строку в массив строк

4. создадим пустой массив, в который будем добавлять массивы с подготовленной информацией.
Затем этот массив будем энкодить в json-строку.

5. в цикле пройдёмся по всем эл-ам массива (который получили в 3-м пункте).

На каждой итерации цикла будем:

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

5.2. проверяем существует ли файл result.json.

5.2.1. если существует, то считываем его и пытаемся декодировать из json-строки в массив.

5.2.2. если декодировать неудалось, то сохраняем его (на всякий случай) и вместо него создаём новый (пустой, естественно).

5.2.3. если декодировать удалось, то просто добавляем к массиву (п. 4) наш подмассив (п. 5.1).

5.3. энкодим наш, теперь уже, заполненный массив (из п. 4) в json-строку.

5.4. записываем в файл нашу json-строку.

После декодинга из json-строки в массив — кодировка строковых данных — «UTF-8».
Если внутри php-файла кодировка другая, то нужно использовать функцию iconv для перекодировки.

Перед энкодингом массива в json-строку все строковые ел-ты массива нужно перекодировать в
кодировку «UTF-8».

PHP функции json_encode(), json_decode() гарантируют сохранность данных только при использовании
кодировки «UTF-8».

Примеры из скрипта:

Здесь мы формируем ассоциативный массив и все строковые эл-ты перекодируем в UTF-8:

// На каждой итерации сохраняем сюда обработанную информацию, затем будем
    // этот массив добавлять в $raw_array[].
    $tmp_array = [
        "name" =>  iconv("windows-1251", "utf-8", $tmp[0]),
        "address" =>  iconv("windows-1251", "utf-8", trim(explode(":", $tmp[1])[1])),  //подчищаем немножко
        "tel" => iconv("windows-1251", "utf-8", trim(explode(":", $tmp[2])[1]))  //подчищаем немножко
    ];

Подготовка для энкодинга (добавляем в существующий массив подготовленную информацию):

$raw_array[] = $tmp_array;

Энкодим массив в json-строку:

Подробнее о константах для функции json_encode см. здесь json.constants

$raw_str = json_encode($raw_array, JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);

Записываем полученную строку в файл:

file_put_contents($path_result_file, $raw_str);

Всё, мы закодировали наш массив в json-строку, которую затем записали в файл.
Теперь, чтобы его декодировтаь нужно:
Считать файл:

$raw_str = file_get_contents($path_result_file);

Декодировать из json-строки в массив.
Если у нас был валидный json-файл, то будет возвращён массив, иначе возвращается булев тип false.
Второй эл-нт указывает ф-ции, что декодировать нужно в массив, а не в PHP-объект:

$raw_array = json_decode($raw_str, true);


Исходники скриптов

<?php
// coding: windows-1251
/**
*  common.php: общие полезные штуки
*/

/**
* Отправить отладочное сообщение в окно отладки.
*
* Печатает отладочное сообщение в консоль отладки, если задана переменна $dbg=true.
*
* @param string $msg Само отладочное сообщение.
* @param string|bool $print_date Печатать ли перед отладочным сообщением дату и время отправки сообщения.
*    + string $print_date: печатать текущее время в отладочном сообщении в заданном формате. Формат
*       печтаемой даты и времени для ф-ции date (default: "d.m.y H:i:s").
*    + bool $print_date: false - не печатать в отладочном сообщении время.
*/
function dbgmsg($msg, $print_date="d.m.y H:i:s") {
    global $dbg;

    if ($dbg) {
        if (is_string($print_date) && $print_date != false) {
            echo "[" . date($print_date) . "]" . " => " . $msg .PHP_EOL;
        } else {
            echo $msg .PHP_EOL;
        }
    }
}

/**
* Функция осуществляющая выкусывание строки по префиксу и постфиксу.
*
* @param string $str1 Строковая переменная в которой будет осуществляться поиск
* @param string $pr1 Префикс
* @param string $pr2 Постфикс
* @param int &$ind_st Индекс номера символа в строке, с кот-го необходимо начинать
*                                 поиск (default: 0)
*
* @return string Возвращает обработанную строку.
*/
// получить строку по префиксам
function get_string($str1, $pr1, $pr2, &$ind_st = 0)
{
   //echo $str1."
"; $ind1 = strpos($str1, $pr1, $ind_st); // echo "index 1 ".$ind1."
"; if($ind1 === false) return ""; $ind2 = strpos($str1, $pr2, $ind1+ strlen($pr1)); //echo "index 2 ".$ind2."
"; if ($ind2 === false) return ""; // запомним стартовый индекс $ind_st = $ind2 + 1; // получим результат $sres = substr($str1, $ind1 + strlen($pr1), $ind2 - $ind1-strlen($pr1)); return trim($sres); } ?> <?php // coding: windows-1251 /** * json_example.php: Пример работы с текстовым форматом обменна данных "JSON". */ /*****************************************************************************/ // Настройки /*****************************************************************************/ // Где запущен XHE. $xhe_host ="127.0.0.1:5753"; // Печатать ли отладочные сообщения? $dbg=true; // Путь к файлу с результатом $path_result_file = "result/result.json"; // Адрес сайта $site = "http://www.yellowpagesrussia.ru/190/893/"; // Ск-ко времени (в секундах) ждать. Для ф-ции sleep. $wt = 1; $wt1 = 1; $wt2 = 2; $wt3 = 3; $wt4 = 4; $wt5 = 5; $wt_long = 10; /*****************************************************************************/ // Подключение необходимых библиотек. /*****************************************************************************/ // XHE lib require "C:\XWeb\Human Emulator Advanced\Templates\xweb_human_emulator.php"; // Полезные штуки require "common.php"; /*****************************************************************************/ // Скрипт /*****************************************************************************/ dbgmsg("Скрипт начал работу."); dbgmsg("", false); // Переходим на сайт $browser->navigate($site); sleep($wt); // Спарсили с сайта содержимое html-тега div с id "content". // На выходе получили массив (с одним эл-ом) с контентом страницы. $content = $element->get_all_inner_texts_by_attribute("id", "content"); // Т.к., $content[0] содержит лишние данные, то их необходимо убрать. // Это можно сделать с помощью функции get_string (обычно находится в // каждом скрипте в tools/functions.php, lib/common.php и т.п.). $content = get_string($content[0], "Фрахт", "Страницы"); // Теперь $content это массив строк. Эл-нты массива содержат информацию (разделенную \r\n) // о предприятиях с сайта. $content = explode("\r\n \r\n", $content); // Массив, в который будем добавлять key-value подмассивы и энкодить в JSON-строку. $raw_array = []; // Пройдёмся в цикле по массиву $content, чтобы заполнить массив $raw_array // нужной информацией перед энкодингом в json-строку. foreach($content as $ck => $cv) { // $ck - content key; $cv - content value // Массив строк. Каждый эл-нт содержит информацию о фирме (название, адрес, тел.) $tmp = explode("\r\n", $cv); // На каждой итерации сохраняем сюда обработанную информацию, затем будем // этот массив добавлять в $raw_array[]. $tmp_array = [ "name" => iconv("windows-1251", "utf-8", $tmp[0]), "address" => iconv("windows-1251", "utf-8", trim(explode(":", $tmp[1])[1])), //подчищаем немножко "tel" => iconv("windows-1251", "utf-8", trim(explode(":", $tmp[2])[1])) //подчищаем немножко ]; // проверяем существует ли файл, если существует, то добавляем записи к файлу, // иначе - создаем новый файл. if($file_os->is_exist($path_result_file)) { // файл уже существует // считываем его $raw_str = file_get_contents($path_result_file); $raw_array = json_decode($raw_str, true); // пробуем декодировать в массив dbgmsg("Файл уже существует."); if (is_null($raw_array)) { // json_decode вернул NULL - json-строка не может быть декодирована в массив. // сохраним этот непонятный файл (на всякий случай) добавив к его названию unix timestamp $tmp_file_path = date_timestamp_get(date_create()); $file_os->move($path_result_file, $path_result_file . "." . $tmp_file_path); // т.к. сейчас $raw_array = NULL, то массив надо переинициализировать. $raw_array = []; $raw_array[] = $tmp_array; // добавили в массив сформированный с нужной информацией массив. // формируем из массива валидную json-строку $raw_str = json_encode($raw_array, JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); // теперь - файла не существует, создаем новый. // записываем в файл готовую сформированную json-строку. //$textfile->write_file($path_result_file, $raw_str); file_put_contents($path_result_file, $raw_str); dbgmsg("Существующий файл оказался какой-то не такой. Переместили его в " . $path_result_file . "." . $tmp_file_path); dbgmsg("Вместо непонятного файла создали новый и записали в него json-строку."); } else { // json-строка нормально декодировалась в массив, значит просто // добавляем в массив нужные нам данные. $raw_array[] = $tmp_array; // формируем из массива валидную json-строку $raw_str = json_encode($raw_array, JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); // записываем в файл готовую сформированную json-строку. //$textfile->write_file($path_result_file, $raw_str); file_put_contents($path_result_file, $raw_str); dbgmsg("С файлом всё ок, добавили в массив нужную информацию, заэнкодили в json-строку, записали в файл " . $path_result_file); } // end if is null } else { // файл не существует, создаем новый. dbgmsg("Файл не существует."); $raw_array[] = $tmp_array; // формируем из массива валидную json-строку $raw_str = json_encode($raw_array, JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); // записываем в файл готовую сформированную json-строку. //$textfile->write_file($path_result_file, $raw_str); file_put_contents($path_result_file, $raw_str); dbgmsg("Создали новый файл " . $path_result_file . " + добавили в него нужный json."); } // end if is file exist } // end of foreach /*****************************************************************************/ // Quit /*****************************************************************************/ dbgmsg("", false); dbgmsg("Скрипт закончил работу."); $app->quit(); ?>


Использованная литература и источники:

Википедия

Wikipedia

json.org

php.net

habrahabr.ru

Скрипты написаны в XHE 4.6.45 MT.

скачать скрипт

Добавить комментарий

*
*

Необходимые поля отмечены*