Обход дерева объектов
Для получения значения текущего узла (вне зависимости от его типа) используют метод DomNode->node_value() или DomNode->get_content() для получения содержимого узла.
Для получения значения атрибута используется метод DomElement->get_attribute (attr_name). А метод DomNode->child_nodes() возвращает массив потомков данного узла.
Для того чтобы сделать обход дерева объектов, полезно еще уметь различать объекты по типам, т.е. определять, является ли узел элементом (тегом), текстом, атрибутом и т.п. Для этого используются специальные константы. XML_ELEMENT_NODE определяет, является ли узел элементом, XML_ATTRIBUTE_NODE определяет, является ли узел атрибутом, и XML_TEXT_NODE определяет, является ли узел куском текста. Эти константы имеют целочисленные значения 1, 2 и 3 соответственно. Использование этих констант полезно, поскольку переводы строки, применяемые для удобочитаемости XML-файлов, тоже становятся узлами.
<?
// сначала делаем то же,
// что и в предыдущем примере
$xmlstr = join('',file('persons.xml'));
if(!$dom = domxml_open_mem($xmlstr)) {
echo "Ошибка при разборе документаn";
exit;
}
$root = $dom->document_element();
// Получаем массив потомков
// родительского узла
// (в нашем случае это массив <person>)
$nodes = $root->child_nodes();
print_r($nodes);
echo "<hr>";
// Начинаем обработку каждого
// узла в массиве
foreach($nodes as $node){
// Если текущий узел – один
// из узлов <person>, то
// продолжаем ее обработку,
// чтобы получить информацию
// об этой личности
if ($node->tagname=='person'){
// Создаем массив, куда
// будем собирать информацию
// о рассматриваемой личности
$currentPers = array();
// Получаем id личности,
// который хранится в атрибуте 'id'
$currentPers['id'] =
$node->get_attribute('id');
// Получаем массив потомков
// <person>. Это вся
// информация о личности
// (<name>,<birth> и т.д.)
$persons_info =
$node->child_nodes();
// Перебираем все дочерние
// узлы $node
foreach ($persons_info as $info){
// проверяем, является ли узел
// элементом (xml-тегом)
if ($info->type==
XML_ELEMENT_NODE) {
// тогда метод tagname
// возвратит имя этого
// элемента (тега), а метод
// get_content() –
// его содержимое
$currentPers[$info->tagname] =
$info->get_content();
}
}
// выводим на экран полученные
// массивы
print_r ($currentPers);
echo "<br>";
}
}
?>
Итак, мы научились обходить дерево XML. Теперь можно попытаться что-нибудь найти в XML-файле. Правда, делать это не совсем удобно опять же из-за переносов строк, которые мы использовали при написании XML-файла. Пусть наш XML-файл записан в строку, а точнее, в нем есть следующая строка:
...
<person id="20">
<name>
<first>Иван</first>
<last>Иванов</last>
</name>
...
Тогда в наш предыдущий пример вставим (после вывода на экран полученных массивов) строчку для поиска электронного адреса Ивана Иванова.
...
$str = $currentPers["email"];
if ($currentPers["name"] ==
"Иван Иванов" )
echo "Здравствуйте, Иван! " .
"Ваш e-mail $str";
...
Добавление новых элементов в XML-документ
Далее разберем задачу, как можно добавить в нашу базу данных новую личность средствами php.
Сначала нужно скопировать описание личности (считаем, что все личности описываются с помощью стандартного набора характеристик, как в файле persons.xml). Это делается с помощью метода DomNode->clone_node(). Таким образом, мы клонируем элемент <person> и все его внутренние элементы (содержание тегов не копируется).
Потом можно установить какие-нибудь значения для элементов описания личности. Например, задать имя человека, дату его рождения и т.п. В конце нужно записать полученное описание личности в качестве потомка корневого элемента в дерево DOM с помощью метода DomNode->append_child(new_node), где в качестве параметра передается созданный объект (новый узел).
В PHP до версии 4.3 перед добавлением потомка к узлу с помощью данной функции этот потомок сначала копировался. Таким образом, новый узел являлся новой копией, которая могла изменяться без изменения узла, переданного как параметр в эту функцию. В более поздних версиях PHP новый узел удаляется из существующего контекста, если он уже есть в дереве. Такое поведение соответствует спецификациям W3C.
Для удаления узла можно воспользоваться методом, применив его к узлу, который требуется удалить, т.е. DomNode->unlink_node().
Заключение
Итак, мы изучили ряд функций, позволяющих манипулировать данными, хранящимися в XML-формате. Это, конечно же, далеко не полный перечень существующих функций. В версии PHP5 он значительно усовершенствован и в большей степени соответствует стандарту DOM. Тем не менее знание приведенных здесь основных функций может оказаться полезным при решении конкретных прикладных задач.
Использование шаблонов в PHP
Что такое шаблоны и зачем они нужны
Что такое шаблон в языке программирования? Можно сказать, что шаблон - это текст с переменными внутри него. При обработке шаблона происходит замена переменных на их значения.
В одной из лекций мы уже рассматривали пример шаблона. Это был шаблон для отображения документов. Пользователь создавал строку текста, размеченного с помощью html-тегов, и вставлял в нее специальные метасимволы (вида <!имя элемента>), которые наша программа впоследствии заменяла на значения соответствующих элементов. Для чего нам был нужен такой шаблон? Чтобы, например, можно было изменить стиль отображения документа, не меняя кода программы.
Наиболее распространенный ответ на вопрос, зачем нужны шаблоны, звучит примерно так: шаблоны нужны для того, чтобы отделить логику работы приложения от способа представления данных, т. е. от дизайна.
Приведенный пример шаблона - один из самых простых. Для его обработки используется только функция подстановки str_replace(). Чаще всего для того, чтобы работать с шаблонами, создают библиотеки классов. В принципе создавать свою библиотеку не обязательно, поскольку существует множество свободно распространяемых библиотек шаблонов, над функциональностью которых трудятся большие коллективы разработчиков, стараясь сделать их универсальными, мощными и быстрыми. Некоторые из таких библиотек мы и рассмотрим. Но для начала сформулируем задачу, на примере решения которой будем демонстрировать использование различных шаблонов.
Итак, задача:
Требуется сгенерировать web-страницу со списком статей, имеющихся в базе данных. Для простоты считаем, что статья имеет название title, автора author, краткое содержание abstract и полное содержание fulltext, которое представлено либо в виде текста в базе данных, либо в виде ссылки на файл. Список должен быть организован так, чтобы при щелчке мышью на названии статьи ее полное содержание появлялось в новом окне.
Шаблоны подстановки
Как можно решить такую задачу способом простой подстановки, т.е. тем методом, которым мы решили задачу отображения документов?
Нужно придумать шаблон для этой страницы и где-то его хранить (в файле или в базе данных). Очевидно, что мы не можем придумать шаблон для всей страницы, потому что не знаем, сколько статей в базе данных. В шаблоне же мы договорились использовать только html и метасимволы <!имя элемента>. Поэтому мы можем написать только шаблон для одной строки списка, который уже программно надо преобразовать в нужное количество строк.
<li><a href="<!fulltext>"
target=new><!title></a>
(<!author>)<br>
<!abstract>
Кроме того, здесь есть еще одна загвоздка - с отображением ссылки на полный текст статьи. Если мы будем действовать по правилу подстановки (менять все метасимволы на их значения из базы данных), то может получиться, что вместо <!fulltext> вставим не ссылку на текст, а сам текст. То есть для этого элемента нужна дополнительная проверка перед заменой и какие-то дополнительные действия в случае, если в поле fulltext содержится текст статьи, а не ссылка на файл. Не будем усложнять себе жизнь и договоримся, что в поле fulltext всегда содержится только ссылка на файл. Тогда задачу можно решить следующим образом: