Парсинг xml

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

Для решения задачи был использован информер, предлагаемый сайтом Центробанка в виде xml-файла.

Решение вроде бы тривиальное, файл парсится стандартной функцией php simplexml_load_file(), которая создает переменную-объект со структурированными данными xml-файла, но…

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

Попытки сохранить  объект, полученный с помощью функции simplexml_load_file() в базе данных wordpress ни к чему хорошему не привели. То есть, объект-то сохранялся, но  уже из базы загружался в совершенно непотребном виде. Структура представления объектов в базе WordPress не могла адекватно сохранить структуру объекта.

К счастью, существует аналог функции парсинга, работающий с текстовой строкой (в которую xml-файл можно загрузить функцией file_get_contents()). Далее в базу WordPress вроде бы можно загрузить xml-файл в виде строчной переменной…

Но и это локальное решение не заработало.  Просмотром кода xml-файла я обнаружил,  что он имел заголовок xml version=»1.0″ encoding=»windows-1251″ . Соответственно и сам файл имел эту «нестандартную» для WordPress кодировку.

Преобразования кодировки файла с помощью функции iconv() тоже оказалось недостаточно — сохраненный в базе текст файла упорно возвращался оттуда в виде «кракозябр».  И только дополнительная замена в тексте файла  «windows-1251″ на «UTF-8″ помогла. Получилась следующая функция:

Selec All Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function load_xml ($pathxml,$opt) {
	$nowopt=get_option( $opt, 'none' );
	if (($nowopt=='none') or (strtotime(date('Y-m-d H:i'))-strtotime ($nowopt['date'])>(3600*LOAD_INTERVAL_HOURS))) {
		$str=file_get_contents($pathxml);
		if ($opt=='currency') {
			$str=iconv("cp1251", "UTF-8", $str);
			$str=str_replace ("windows-1251","UTF-8",$str);
		}
		$xml_obj= simplexml_load_string($str);
		$newdat['obj']=$str;
		$newdat['date']=date('Y-m-d H:i');
		update_option( $opt, $newdat);
	} else {
		$xml_obj=simplexml_load_string($nowopt['obj']);
	}
	return $xml_obj;
}

Передача в параметрах функции адреса xml-файла и «имени» переменной базы не должна удивлять — на базе функции я сделал плагин, который выводил несколько информеров.

Константа LOAD_INTERVAL_HOURS в функции задает интервал подгрузки данных информера. Теперь только раз в несколько часов один из посетителей сайта получает несколько замедленную загрузку страницы.

И от этого недостатка при желании тоже можно избавиться — достаточно загрузку данных информера производить с помощью cron.

 

***

Комментариев - 4

  • Поконкретней бы. Вы куда пишете данные xml? В произвольные поля?

    • Если внимательно посмотреть код плагина, то видно, что данные пишутся в таблицу wp_options. С помощью функции update_options()

      • Спасибо. Не разобрался с кодом. Есть у меня парсер xml — но у него на каждую запись своё значение. Не думаю что почти 4000 параметров в wp-options писать — хорошая затея. Пока склоняюсь к произвольным полям. Я проблему с загрузкой xml решил координально — по запросу. Ajax срабатывает по клику на кнопке. т.к. не смог записать хмл в базу.

        • Да, конечно, при привязке к записям лучшее решение — произвольные поля. Я иногда даже свой тип данных под хранение завожу. А Ajax в моем примере был неприменим. Проблема была в том, что в изначальном решении xml-запрос производился при каждой смене страницы каждым пользователем. Что добавляло не менее секунды к загрузкам страниц сайта. Поэтому привязка запроса к cron убирала это время. Ну и по мелочи снимала часть нагрузки с хостинга.

Хотите обсудить? Оставьте комментарий