| В свете последних тем на форуме, связанных с работой разного рода XML-сервисов у меня возник вопрос, почему во многих случаях для разбора данных применяются регулярные выражения? Вроде бы сейчас у большинства хостеров стоит PHP5 и поэтому для удобной работы с XML не требуется даже подключения модуля xmlrpc, а вполне достаточно встроенных классов DOM.
Хочу оговориться, что я ни в коем случае не против регулярных выражений, их знание в любом случае необходимо, но не будет ли более правильным, при работе с какой-то технологией, использование методов, созданных специально для нее?
На мой взгляд, любой Xpath-запрос применительно к XML намного нагляднее сложных (а зачастую весьма громоздких) шаблонов PCRE.
Чтобы не быть голословным, приведу примеры функций для получения курсов валют и погоды.
При необходимости, могу также предоставить примеры разбора любого XML-based формата (например RSS ;-).
Курсы валют
Функции передается два параметра - символьный код валюты (можно посмотреть на сайте ЦБ) и необязательный - дата (при отсутствии используется текущая).
Функция возвращает массив, в котором первым элементом будет дата изменения котировок, а вторым - хеш, соответствующий узлу Valute в XML, где ключами являются имена узлов, а значениями - соответствующие текстовые узлы.
<?php
function get_currency($ccode, $date=false) {
static $xmld,$xmlm = false;
$xml_url = "http://www.cbr.ru/scripts/XML_daily.asp?date=$date";
$ccode = strtoupper($ccode); if(!$date) $date = date('d/m/Y');
$daily = array('AUD', 'GBP', 'BYR', 'DKK', 'USD', 'EUR',
'ISK', 'KZT', 'CAD', 'CNY', 'NOK', 'XDR',
'SGD', 'TRY', 'UAH', 'SEK', 'CHF', 'JPY',
);
if(in_array($ccode, $daily)) $xml = @$xmld = $xmld ? $xmld : DOMDocument::load($xml_url);
else $xml = @$xmlm = $xmlm ? $xmlm : DOMDocument::load($xml_url.'&d=1');
if(!$xml) return false;
$xpath = new DOMXpath($xml);
$cdate = $xml->firstChild->getAttribute('Date');
$snippet = $xpath->query("/ValCurs/Valute[CharCode='$ccode'][1]")->item(0);
if(!$snippet) return false;
$result = array();
$params = $xpath->query("child::*", $snippet);
foreach($params as $element)
$result[strtolower($element->nodeName)] =
function_exists('iconv') ? iconv('UTF-8', 'CP1251', $element->nodeValue) :
(function_exists('libiconv') ? libiconv('UTF-8', 'CP1251', $element->nodeValue) : $element->nodeValue);
return array($cdate, $result);
}
?>
|
Особенности:
При отсутствии на сервере расширений iconv или libiconv, название валюты будет в кодировке UTF-8.
При получении курсов нескольких валют в пределах одного выполнения скрипта, запрос к серверу ЦБ происходит не более 1(2) раз(а) благодаря использованию статических переменных.
Использование функции выглядит так:
list($lastdate, $result) = get_currency('EUR');
|
Прогноз погоды с gismeteo.ru
Функции передается один параметр - код нужного города (берется с сайта gismeteo)
на выходе имеем хеш вида: town=>Название города, forecast=>массив с прогнозами.
Для массива прогнозов, ключ элемента представляет собой метку времени UNIX для даты, на которую составлен прогноз, а значение - двумерный хеш всяких параметров и значений.
Проще сделать print_r(get_meteo(27612)); чем описывать их все :)
<?php
function get_meteo($town_id) {
if(!intval($town_id)) return false;
$xml_url = "http://informer.gismeteo.ru/xml/{$town_id}_1.xml";
$xml = DOMDocument::load($xml_url);
if(!$xml) return false;
$result = array();
$xpath = new DOMXpath($xml);
$temp = $xpath->query("//TOWN[@index=$town_id]/@sname");
$result['town'] = urldecode($temp->item(0)->nodeValue);
$temp = $xpath->query('FORECAST', $temp->item(0)->parentNode);
foreach($temp as $element) {
$tmp = array();
$date = $xpath->query("@year|@month|@day|@hour", $element);
foreach($date as $param) $tmp[$param->nodeName]=$param->nodeValue;
$date = strtotime("{$tmp['year']}-{$tmp['month']}-{$tmp['day']} {$tmp['hour']}:00:00");
$childs = $xpath->query('child::*', $element);
foreach($childs as $node) {
$tmp = array();
$qres = $xpath->query("@cloudiness|@precipitation|@rpower|@spower|@min|@max|@direction", $node);
foreach($qres as $param) $tmp[$param->nodeName]=$param->nodeValue;
$result['forecast'][$date][strtolower($node->nodeName)] = $tmp;
}
}
return $result;
}
?>
|
Ну а теперь, полезные ссылки:
DOM functions
Описание Xpath
Примеры Xpath | |