PHP и XML

Итак, поговорим об XML. Что же это такое и почему многие профессиональные программисты предпочитают его всем другим форматам? И почему так много хвалебных отзывов со стороны тех, кто с ним столкнулся? И почему, наконец, так мало негативных отзывов от тех, кто с ним не сталкивался :-)? XML как язык (а это именно язык, только не программирования, а разметки) сформировался сравнительно недавно — официально первая редакция его спецификации была опубликована в 1998 году. Формат этот оказался настолько удачным, что сразу пришелся ко двору, и его реализации разошлись практически по всем языкам программирования (правда, пока еще в виде внешних модулей или обработчиков) — от Delphi до PHP. Однако русскоязычной документации по нему мало, а сам язык настолько масштабируем и гибок, что описать все области его применения просто невозможно. Поэтому отечественные программисты еще только начинают постигать тайны XML и пока лишь пытаются применять его на практике.

Аббревиатура XML расшифровывается и переводится как «расширяемый язык разметки». И в этом вся его суть. В принципе, программист сам определяет формат файла и сам пишет его обработчик, используя для этого предоставляемые языком средства или разрабатывая собственные. Теперь никому не нужны километры исходного кода для обработки сотен текстовых файлов — все это легко заменяется одним XML-файлом и одним парсером (обработчиком).

XML-файл является обыкновенным текстовым файлом, данные которого организованы таким образом, чтобы создать иерархическую структуру (дерево) тэгов. Имена и атрибуты тэгов программист придумывает самостоятельно, а правила их написания аналогичны таковым в HTML. Например, для книжного магазина:

<?xml version="1.0" encoding="UTF-8"?>
<shop>
 <book author=”Donald Knuth”>Art of programming</book>
 <book author=”Vasily Golovachev”>Magacitly</book>
</shop>


Как видите, даже отвлеченный от программирования человек может понять, о чем идет речь в этом файле. Таким нехитрым способом, применяя древовидную структуру организации данных, разработчики достигают полного отделения содержимого (XML) от дизайна (HTML и прочее), в чем и состоит цель рассматриваемого языка разметки.

Теперь об основных понятиях XML-разметки. Количество тэгов в файле не ограничено, равно как и количество их атрибутов. XML-документ должен быть составлен корректно, в соответствии со следующими правилами, многие из которых перекликаются со спецификацией HTML:

1. <?xml version="1.0"?> — в первой строке всегда содержится версия спецификации, но могут быть и дополнительные атрибуты — например, кодировка символов документа.

2. В документе присутствует один и только один корневой элемент (парный тэг <shop> в нашем случае), подобно <html></html> в языке HTML. Все дочерние элементы могут содержать любое количество вложенных тэгов, которые, в свою очередь, тоже могут содержать любое количество потомков, за счет чего и обеспечивается древовидность.

3. Все без исключения тэги должны иметь соответствующие закрывающие элементы. Если в HTML можно было, например, опустить некоторые закрывающие тэги, и это считалось правильным даже в соответствии со спецификацией, то в XML это недопустимо, так как моментально вызовет ошибку обработки. Правда, если в тэге не планируется создавать никаких вложенных элементов (будь то содержимое или другой тэг), то закрыть его можно несколько проще (например, <song name="Only you" /> вместо <song name="Only you"></song>)

4. Все атрибуты тэгов нужно заключать в кавычки — двойные или одинарные.

5. Все остальные правила, дабы не загромождать статью, читайте в спецификации, которая находится по адресу http://www.w3.org/TR/REC-xml.

PHP и XML


Итак, с XML более-менее разобрались. Во всяком случае, несложный структурированный файл в соответствии с правилами XML-разметки вы создать уже сможете, особенно зная основы HTML. Теперь давайте приступим к реализации функций обработки XML-содержимого на языке PHP.

Думаю, не стоит особо распространяться о пользе PHP как серверного языка программирования. Все возможности Perl плюс «еще кое-что» — и мы имеем полноценный интерпретируемый язык программирования, выполняемый на стороне сервера. В дальнейшем предполагается, что сервер и PHP у вас уже установлены и должным образом настроены на совместную работу, и что вы имеете общие понятия об их функционировании и программировании (начинающим программистам рекомендуем ознакомиться с циклом Артема Шманцырева «Сервер племени апачей», МК №№38-40, 42, 44, 46, 50, 4, 9 (209-211, 213, 215, 217, 221, 227, 232) — примеч. ред.) Многие хостинг-провайдеры — это в основном относится к платным хостингам — предоставляют PHP, в конфигурации которого уже доступны модули обработки XML. Для домашней же платформы могу порекомендовать следующее.

В последние версии PHP (начиная с версии 4.3.0 для платформы Windows, как самой распространенной) включена библиотека php_domxml.dll, которую нужно подключить к интерпретатору для получения доступа к функциям обработки XML (подобная библиотека есть и в Linux, но там она подключается несколько иначе). Эта библиотека находится в каталоге extension_dir, прописанном в конфигурационном файле php.ini, который в свою очередь лежит (или должен лежать) в вашей папке Windows. В этом же файле раскомментируйте строчку extension=php_domxml.dll, и вы получите возможность оперировать документами XML, применяя объектную модель Document Object Model, на которой мы сегодня подробно остановимся. Кстати, рассматривать возможности PHP по работе с XML-файлами мы будем на простейшем примере — мы напишем собственную гостевую книгу. Пример, конечно, идеализирован, но на серверах со скриптами я пока еще не встречал гостевых книг, написанных с применением XML. Поэтому, надеюсь, сегодняшние примеры будут для вас не только интересными, но и полезными.

Для гостевой книги мы на сервере создадим файл с именем guest.xml, который будет содержать все оставленные записи в следующем формате:

<?xml version="1.0" encoding="UTF-8"?>
<guestbook>
 <message date="01.01.04" time="11:22:25" author="Cosmic" email=“cosmic@mail.zp.ua” subject="New GB presented">
  Message body. No HTML tags here.
 </message>
 <message date="01.01.04" time="12:22:25" author="Cosmic" email=“cosmic@mail.zp.ua” subject="This is a subject">
  Another message body
 </message>
 <message date="01.01.04" time="10:22:25" author="Cosmic" email=“cosmic@mail.zp.ua” subject="i?ia?aiia">
  Message body. Attention! Subject in UTF-8 encoding!
 </message>
</guestbook>

Как следует из первой строчки, наш XML-файл будет хранить данные в кодировке UTF-8. Для чего это нужно, вы узнаете чуть позже. Корневой элемент <guestbook> содержит множество дочерних элементов <message>, которые характеризуются атрибутами date (дата), time (время), author (автор), email (почтовый адрес) и subject (тема). В теле элемента <message> находится собственно тело сообщения. Как видите, все интуитивно понятно и немножко похоже на базу данных, в которой поля мы называем так, как сами того хотим.

Перед тем как приступить к написанию самого скрипта, хочу сказать, что в PHP функции работы с XML пока реализованы экспериментально (правда, в версии 5.0 на XML сделана особая ставка, вот только версия эта пока еще находится в состоянии беты, следовательно, переходить на нее пока еще не стоит). Это значит, что приведенные скрипты могут не работать при наличии других версий PHP, не соответствующих указанной. К тому же мои скрипты далеки от совершенства в плане производительности и красоты написания. Поэтому не нужно заваливать мой бедный почтовый ящик гневными письмами. Мое дело, как автора, — натолкнуть вас на мысль, а реализация этой мысли остается исключительно за вами.

PHP поддерживает два модуля, осуществляющие XML-парсинг. Первый называется SAX (Simple API for XML). В силу сложности и ограниченной функциональности (с помощью SAX невозможно записать данные в XML-файл — он поддерживает только чтение), этот интерфейс нами сегодня рассматриваться не будет. Второй модуль представляет гораздо больший интерес с точки зрения разработчика, так как позволяет более наглядно работать с XML-файлом, причем поддерживаются операции и чтения, и записи. Называется он DOM (Document Object Module) и реализуется в PHP следующим образом.

С помощью функции domxml_open_file, вызываемой с именем XML-файла в качестве параметра (в нашем случае — guest.xml), все дерево XML-элементов из файла загружается в память компьютера-сервера (в переменную). Это значит, что никакие изменения, произведенные с открытым файлом, не вступят в силу до его принудительной записи на диск. Эта технология очень удобна, так как позволяет десять раз перепроверить корректность произведенных над файлом действий перед тем как окончательно его сохранить. Вообще, корректности в формате XML уделено огромное внимание, что не может не сказаться на его реализациях в языках программирования.

В XML-файле, как уже было сказано, может существовать только один корневой элемент. Корневой элемент можно получить, используя функцию document_element(), вызываемую без параметров и возвращающую объект. В полученном объекте хранятся все дочерние элементы (тэги <message>), которые мы можем получить, вызвав функцию child_nodes(), возвращающую массив дочерних тэгов. Теперь, пройдясь по полученному массиву циклом foreach, можно получить атрибуты каждого из дочерних элементов (функция get_attribute(), вызываемая с именем атрибута в качестве параметра) и содержимое этих элементов (функция get_content() без параметров). Каждый элемент, дочерний для корневого, может быть корневым для вложенных элементов, если таковые имеются. В таком случае их можно также получить во вложенном цикле foreach, пройдясь им по элементу верхнего уровня.

Для нашей гостевой книги скрипт чтения сообщений будет выглядеть следующим образом:

// открытие XML-файла
$xml = domxml_open_file('guest.xml');

// получение корневого элемента
$root = $xml->document_element(); 
// получение массива вложенных тэгов (потомков)
$nodes = $root->child_nodes(); 

foreach($nodes as $node) {
 // если имя потомка соответствует необходимому...
 if ($node->node_name() == 'message') {
 // ...заполняем именованный массив текущего сообщения данными из файла...
 $currentMessage['date'] = $node->get_attribute('date');
 $currentMessage['time'] = $node->get_attribute('time');
 $currentMessage['author'] = $node->get_attribute('author');
 $currentMessage['email'] = $node->get_attribute('email');
 $currentMessage['subject'] = $node->get_attribute('subject');
 $currentMessage['content'] = $node->get_content();
 // ... и добавляем заполненный элемент в массив
 $messages[] = $currentMessage;
 }
}


После выполнения скрипта мы получаем заполненный массив $messages, пройдясь по которому в цикле foreach, мы запросто получаем сообщения и выводим их в тело страницы:

foreach($messages as $item) {
 echo $item['date'];
 echo $item['time'];
 echo utf8_decode($item['author']);
 echo $item['email'];
 echo utf8_decode($item['subject']);
 echo utf8_decode($item['content']);
}


В результате выполнения скрипта на страничку в одну строчку выведутся все сообщения из гостевой книги. Я намеренно не делаю никакого оформления (например, можно было бы вывести все сообщения в таблице, разделив все поля и сделав сообщение удобочитаемым), так как статья в этом случае растянется на десяток номеров. Еще раз повторю, что моя задача — натолкнуть вас на идею. Все остальное — дело вашего личного вкуса и предпочтений. Рабочий вариант гостевой вы можете посмотреть по адресу http://www.cosmic.net.ua/gb.

Как я уже говорил, модель DOM позволяет не только читать данные из XML-файла, но и записывать их, добавляя новые элементы или атрибуты. Для того чтобы записать данные, нужно снова открыть XML-файл с помощью функции domxml_open_file и получить корневой элемент дерева (функция document_element()). Далее, с помощью функции new_child() в конце множества имеющихся дочерних тэгов создаем новый дочерний элемент. Функция принимает два параметра — название элемента и собственно его содержимое. Атрибуты дочернего тэга <message> устанавливаются при помощи функции set_attribute(), в качестве параметров принимающей название атрибута и его значение.

Так как мы записываем сообщения гостевой книги, мы их должны сначала получить из массива $_GET или $_POST, в который они должны быть переданы из формы (если вы не знаете, как это делается, можете прочесть об этом в моих предыдущих статьях). Из полученных данных мы готовим именованный массив атрибутов, которые в будущем будут записаны в тэг <message>:

$msgToAdd = array(
 'date' => date("d.m.y"),
 'time' => date("H:i:s"),
 'author' => utf8_encode($author),
 'email' => $email,
 'subject' => utf8_encode($subject)
)


Как видите, перед записью переменных $author и $subject (а в будущем и тела сообщения), мы перекодируем их в кодировку UTF-8. Это делается по той причине, что на данном этапе PHP, к сожалению, не поддерживает кодировку Windows-1251 в XML-файлах. Это значит, что при попытке записать сообщение на русском языке скрипт будет выдавать ошибку. Поэтому приходится кодировать символы в промежуточную кодировку (функция utf8_encode), а потом при чтении их декодировать (функция utf8_decode). Весь скрипт записи нового сообщения примет примерно следующий вид:

$xml = domxml_open_file('guest.xml');
$root = $xml->document_element();

// $message — тело сообщения из массива $_GET или $_POST
$msgNode = $root->new_child('message',utf8_encode($message));

$msgNode->set_attribute('date',$msgToAdd['date']);
$msgNode->set_attribute('time',$msgToAdd['time']);
$msgNode->set_attribute('author',$msgToAdd['author']);
$msgNode->set_attribute('email',$msgToAdd['email']);
$msgNode->set_attribute('subject',$msgToAdd['subject']);

$text = $xml->dump_mem();
$fp = fopen('guest.xml','w');
fwrite($fp,$text);
fclose($fp);


Здесь появляется новая функция dump_mem(), скидывающая все содержимое памяти в переменную $text, которая в дальнейшем записывается на диск стандартными операторами записи. Как видите, все элементарно просто, безопасно и корректно — пока вы не убедитесь, что все операторы выполнены корректно, ваш файл не будет записан и, следовательно, увеличивается надежность хранения данных и уменьшается вероятность их потери.

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

Так что как всегда выбор остается за вами, уважаемые читатели.




Рекомендуем почитать

 

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


Ваше имя:


Комментарий:


Введите: Картинка