Использование XML Paser Functions при работе с шаблонами.
Мы рассмотрим разделение данных и кода на основыве на языке XML.
Рассмотрим следующую задачу: У нас есть много клиентов, и практически каждый из них, желает видеть на своем сайте гостевую книгу. Каждый раз изменять исходный текст гостевой книги нам уже поднадоело. И речи уже не идет о том, что ошибку, которую мы нашли, устанавливая гостевую книгу в восемнадцатый раз пришлось рукам исправлять в на предыдущих семнадцати сайтах.
Для того, чтобы избежать подобной проблемы, необходимо данные отделить от кода. Нам бы хотелось чтобы внешний вид гостевой книги хранился в отдельном файле, динамические данные (записи) хранились в базе данных, а код в отдельном каталоге.
Так, мы могли бы быстро исправить допущенную ошибку простой заменой старого кода на новый, при это сохранилось бы оригинальное оформление.
Опишем шаблон гостевой книги с помощью XML следующим образом:
Каждый шаблон состоит их основной секции <guestbook></guestbook> внутрь которой может помещаться секция <records></record> описывающая одну запись в гостевой книге.
Кроме того, там может находится одиночный тег <include />, не место которого будет вставлен документ описанный с помощью свойства url, например:
<include url="../bottom.htm />
Ниже приведена сокращения схема описанного документа: <?xml version="1.0" encoding="windows-1251"?> <guestbook> <include url="../top.html" /> <record> тело одной записи </record> <include url="../bottom.htm /> </guestbook>
Осталось малость - написать программу, которая превратит описанный выше шаблон в HTML документ, содержащий как внешнее оформление, так и динамически изменяемые данные (записи в гостевой книге)
Для обработки шаблона мы будем использовать XML Parser functions ( HTTP://www. PHP. Net/ Manual/en/ref.xml.php). Это расширение PHP предоставляет доступ к функциям библиотеки Expat, автором которой является Джеймс Кларк (James Clark). Библиотека Expat написана на языке C++ и предназначенная для разбора XML документов основанного на событиях. Она не проверят XML документ на ошибки и не работает с объектой моделью XML документа, так как это делают некоторые другие библиотеки (например tinyXML)
В версии PHP 4 XML Parser functions поддерживаются по умолчанию.
Перейдем непосредственно к написанию программы - обработчика шаблона.
Сначала считаем шаблон в переменную $xmldata:
<? $xmldata=implode("",file("template.xml")); // Ассоциативный массив - хранит данные, соответствующие тегам. $TMPL=Array(); // Обрабатываемый тег $ce=""; /* ... пропущено подключение к серверу MySql ... */ $result=mysql_query("SELECT * FROM guestbook_database");
В переменную $html мы будет выводить результат работы нашего скрипта. В самом конце мы сделаем просто Print $html;
$html="";
Создаем объект обработчик XML документа
$xml_parser = xml_parser_create();
Задаем ему опции и обработчики. Функция startElement() будет вызываться, когда в XML документе встретится открывающийся тег. Функция endElement() будет вызываться, когда будет встречен закрывающий тег. Для данных (то, что внутри тега) будет вызываться функция characterData()
if (!xml_parse($xml_parser, $xmldata)) { $error=sprintf("Ошибка в шаблоне: %s at line %d", xml_error_string(xml_get_error_code($xml_parser)), xml_get_current_line_number($xml_parser)); die(); } xml_parser_free($xml_parser);
Вывод данных
print $html;
Теперь рассмотрим основную часть - это три функции-обработчика:
В глобальной переменной $ce запомним название обрабатываемого тега, чтобы в обработчике characterData() знать к какому элементу массива $TMPL дописывать содержимое.
function startElement($parser, $name, $attrs) {
GLOBAL $ce,$TMPL,$html;
switch ($name) {
case "INCLUDE":
$html.=@implode("",@file($attrs["URL"]));
break;
}
$TMPL[$name]="";
$ce=$name;
}
function endElement($parser, $name) {
GLOBAL $ce,$TMPL,$result,$html;
switch ($name) {
case "RECORD":
while ($D=mysql_fetch_array($result)) {
$t=$TMPL["RECORD"];
$t=str_replace("__NAME__",$D["name"],$t);
$t=str_replace("__EMAIL__",$D["email"],$t);
$t=str_replace("__COMMENT__",$D["comment"],$t);
$html.=$t;
}
break;
}
$ce="";
}
function characterData($parser, $data) {
GLOBAL $ce,$TMPL,$html;
switch ($ce) {
case "RECORD":
$TMPL[$ce].=$data;
break;
default:
$html.=$data;
}
}