Как и обещал, познакомлю своих читателей с технологией создания и обработки XML файлов. На сегодняшний день в XML формате хранят всё, что попадается на глаза. Так же XML хорошо себя зарекомендовал как формат передачи данных между клиентом и сервером в Ajax приложениях. Кроме того на языке XML обмениваются данными различные он-лайн сервисы, в которых так же применяется расширенный формат - XML-RPC. Но обо всём по порядку.

XML так же широко распространён за пределами онлайна. В этом формате очень удобно хранить конфигурационные файлы. Более того, даже Microsoft Office 2007 хранит все создаваемые документы в XML структурах! Это уже говорит о многом. Даже существует формат MusicXML, который представляет midi данные в более понятном для человека формате. Я более чем уверен, XML найдёт применение в любой области, куда могут дотянуться руки программистов.

Неискушённый читатель обязательно спросит: зачем же весь этот гемморой по портированию данных из одного представления в другое? Действительно, с первого взгляда невозможно понять всей прелести хранения данных в XML. Это переход на открытые форматы, не нужно сидеть сутками, изучая спецификацию нужного формата или заниматься реверсивным инженерингом, достаточно открыть XML файл и за пару минут понять структуру данных. Благодаря этому, в разы уменьшается время разработки приложений и вместо обработки хитроумного формата можно уделить больше времени для пользовательской части приложения. Да, XML занимает больше дискового пространства, парсеры уступают по скорости прямому доступу к файлам. Но никто не запрещает применять алгоритмы сжатия и шифрования, а так же кеширование XML структур. Но о кешировании я пока что не ничего не слышал. Подведу итог: XML открытый и кроссплатформенный формат.

В этой статье будет рассмотрено:
1) Общая структура XML файла
2) Способы генерации XML данных
3) Обработка (парсинг) XML данных

Для знакомых с HTML (я надеюсь, что большинство моих читателей им владеет) проблем разобраться в XML не будет. Абсолютно тоже самое: открывающие и закрывающие теги, вложенные друг в друга теги (родители и потомки), атрибуты тегов. Если Вам знакомы эти определения и не вызывают трудностей - то можно считать XML Вы уже освоили. А для тех, кто знаком с понятием семантической вёрстки - можно считать начальным знанием XML. Суть XML - построить древовидную (иерархическую) структуру данных, для последующего хранения, передачи и обработки. Рассмотрим простейший пример XML файла.

<?xml version="1.0" encoding="utf-8" ?>
<rss version="2.0">
	<channel>
		<title>Блог Холи Дайвера</title>
		<description>Блог о web-программировани, создании и продвижении сайтов.</description>
		<link>http://holydiver.ru/</link>
		<lastBuildDate>Wed, 18 Nov 2009 17:27:59 -0000</lastBuildDate>
		<item>
			<title>Нововведения в статистике Яндекс.Директ</title>
			<link>http://holydiver.ru/posts/wordstat-news.html</link>
			<description><![CDATA[<p>26 марта 2009 года в статистике Яндекс.Директ (<a href="http://wordstat.yandex.ru/">wordstat.yandex.ru</a>) произошёл ряд изменений.</p>]]></description>
			<pubDate>Sat, 28 Mar 2009 20:43:05 +0000</pubDate>
		</item>
		<item>
			<title>Восстановление MySQL таблиц</title>
			<link>http://holydiver.ru/posts/mysql-repair-tables.html</link>
			<description><![CDATA[<p>Вчера позвонил знакомый и описал невероятную историю.</p>]]></description>
			<pubDate>Sat, 28 Mar 2009 15:12:08 +0000</pubDate>
		</item>
	</channel>
</rss>
 

Первая строка говорит о том, что данные находятся в XML формате и в кодировке UTF-8. Очень рекомендую использовать именно UTF-8 при обработке XML данных, иначе могу возникать ситуации с неправильным определением кодировки. Далее следует обязательный корневой элемент с любым именем, в данном случае <rss> с аттрибутом version=”2.0″. Абсолютно неважно, как Вы будете называть теги, всё зависит от поставленных задач и фантазии, главное чтобы имена соответствовали спецификации. Далее всё должно быть предельно понятно, если возникают трудности с восприятием структуры XML формата, лучше пойти и заняться более простыми вещами.

Вы должны были обратить внимание, что часть данных заключена в какое-то непонятное “<![CDATA[" и "]]>”. Это очень полезная вещь! Если тег содержит HTML или XML данные, которые не нужно парсить (обрабатывать), заключение из в конструкцию <![CDATA[]]> предотвратит это. Возможно выглядит несовсем понятно, но когда перейдём к примерам - всё прояснится.

Первым делом нужно сгенерировать XML данные. Конечно можно делать по принципу echo ‘<title>Восстановление MySQL таблиц</title>’; и в том же духе, но такой убогий вариант нас не устраивает! Для более правильной генерации XML потребуется PHP5 с установленным модулем SimpleXML. Если Вы ещё не перешли на PHP5 - мне очень жаль. Можно конечно воспользоваться различными костылями, в виде функций xml2array или XML Parser функций. В этих случаях Вы не сможете быть уверенными, что при изменении структуры данных, приложение не потеряет работоспособность и его не придётся модифицировать.

<?php

    //    ЗАПРОС НА RSS ФИД
    if(isset($_GET['feed'])) {
        //    ЗАДАНИЕ ТИПА ДОКУМЕНТА И КОДИРОВКИ
        header('Content-Type: text/xml;charset=utf-8');

        //    СОЗДАНИЕ ЭКЗЕМПЛЯРА КЛАССА И ПЕРЕДАЧА ЕМУ ЗАГОЛОВКА
        $xml = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" />');

        //    ЗАПОЛНЕНИЕ ИНФО О КАНАЛЕ
        $channel = $xml->addChild('channel');
        $xml->channel->addChild('title', 'Блог Холи Дайвера');
        $channel->addChild('description', 'Блог о web-программировани, создании и продвижении сайтов.');
        $channel->addChild('link', 'http://holydiver.ru/');
        $channel->addChild('lastBuildDate', date('r'));    //    Дата в формате RFC 2822

        //    ДОБАВЛЕНИЕ ПЕРВОЙ ЗАПИСИ
        $item = $channel->addChild('item');
        $item->addChild('title', 'Нововведения в статистике Яндекс.Директ');
        $item->addChild('link', 'http://holydiver.ru/posts/wordstat-news.html');
        $item->addChild('description', '<![CDATA[<p>26 марта 2009 года в статистике Яндекс.Директ (<a href="http://wordstat.yandex.ru/">wordstat.yandex.ru</a>) произошёл ряд изменений.</p>]]>');
        $item->addChild('pubDate', date('r'));

        //    ДОБАВЛЕНИЕ ВТОРОЙ ЗАПИСИ
        $item = $channel->addChild('item');
        $item->addChild('title', 'Восстановление MySQL таблиц');
        $item->addChild('link', 'http://holydiver.ru/posts/mysql-repair-tables.html');
        $item->addChild('description', '<![CDATA[<p>Вчера позвонил знакомый и описал невероятную историю.</p>]]>');
        $item->addChild('pubDate', date('r'));

        //    ВЫВОД XML СТРУКТУРЫ В БРАУЗЕР С ПРЕОБРАЗОВАНИЕМ HTML СУЩНОСТЕЙ В СООТВЕТСТВУЮЩИЕ СИМВОЛЫ
        echo html_entity_decode($xml->asXML());
    }

?>

Таким нехитрым PHP кодом выводится полноценная RSS лента. Да, RSS лента это XML структура. Если сохранить этот фрагмент кода в файл и обратиться к нему с добавлением имя файла + “?feed”, то можно посмотреть сгенерированное содержимое. В данном примере использованы всего 3 функции для работы с XML. SimpleXMLElement() - создаёт новый объект для работы. $object->addChild(name, value) добавляет новый элемент внутрь XML объекта. $object->asXML() - возвращает XML код объекта. Чтобы добавить новый элемент “item” в элемент “channel” нужно выполнить код $xml->channel->addChild(’item’), а чтобы в этот “item” добавить “title” - $xml->channel->item->addChild(’title’, ‘текст’). Чем больше уровень вложенности, тем длиннее будет выглядеть команда. Но можно сделать всё проще, каждый вызов функции addChild() возвращает ссылку на созданный элемент. То есть если написать $item = $xml->channel->addChild(’item’), то переменная $item будет ссылаться на $xml->channel->item. Вот такое простое сокращение кода и увеличение читаемости. Надеюсь получилось достаточно понятно. При выводе я использовал функцию html_entity_decode(), так как по-умолчанию SimpleXML превращает все HTML символы в их заменители, например, < d &lt;. На этом генерация XML кода закончена, переходим к парсингу.

Я не просто такрешил сделать вывод RSS фида через параметр “?feed”. Было бы глупо для такого простого примера создавать отдельные файлы для PHP скриптов генерации и парсинга XML данных. Поэтому добавляем в уже созданный файл следующий код.

<?php

    //    ПРОСЛОЙКА ДЛЯ mb_convert_encoding()
    function dataconv($string) {
        return mb_convert_encoding($string, 'WINDOWS-1251', 'UTF-8');
    }

    if(!isset($_GET['feed'])) {
        //    ЗАДАНИЕ ТИПА ДОКУМЕНТА И КОДИРОВКИ
        header('Content-Type: text/html;charset=windows-1251');

        //    ПОЛУЕНИЕ ДАННЫХ ИЗ ФИДА
        $data = file_get_contents('http://'.$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'].'?feed');
        //    ПАРСИНГ
        $data = new SimpleXMLElement($data);
        $channel = $data->channel;

        echo '<html>';
        echo '<head>';
        echo '<meta http-equiv=content-type content="text/html;charset=windows-1251">';
        echo '<title>'.dataconv($channel->title.': Лента новостей').'</title>';
        echo '</head>';
        echo '<body>';

        echo '<h1><a href="'.$channel->link.'">'.dataconv($channel->title).'</a></h1>';
        echo '<pre>'.dataconv($channel->description).'</pre>';

        //    ПРОХОД ПО ВСЕМ ЭЛЕМЕНТАМ item
        foreach($channel->item AS $k => $v) {
            echo '<h3><a href="'.$v->link.'">'.dataconv($v->title).'</a></h3>';
            echo '<p>'.dataconv($v->description).'</p>';
        }

        echo '</body>';
        echo '</html>';
    }

?>

Обработка XML данных выглядит ещё проще, чем их генерация! В данном применре я немного схитрил: фид генерируется в кодировке UTF-8, а обработка и вывод HTML страницы в WINDOWS-1251. Это чтобы показать, что нет никакой сложности работы в разных кодировках. Принцип действия прост до безумия: сначала в переменную $data записывается RSS фид, потом в эту же переменную записывается SimpleXML, содержащий эти же данные. Самым интересным моментом сдесл является цикл foreach, перебирающий все элементы item в RSS фиде. Именно так нужно поступать, когда внутри одного родителя содержится несколько элементов с одинаковыми именами. Так же к ним можно полукчить доступ через указание индекса в массиве, то есть $channel->item[0]->title, $channel->item[1]->title и так далее.

На этоми закончу первую статью о XML. Буду рад ответить на все вопросы, плохо раскрытые в этой статье.

Опубликовано 26.11.2009в 23:11. В рубриках: Cкрипты, PHP, Полезное. Вы можете следить за ответами к этой записи через RSS 2.0. Вы можете оставить свой отзыв или трекбек со своего сайта.

Оставьте отзыв

Это не спам.
сделано dimoning.ru