Главная страница статей --> Хитрости при программировании php, заметки по базам данных

Спецификация и функции DOM в PHP

Источник: realcoding.net

[2 страница]

Копирование элементов


Пока модуль DOM XML не совсем соответствовал спецификации DOM, с этим делом была совсем блажь: получаешь объект элемента и добавляешь его к элементу другого документа. Теперь надо перед этим клонировать элемент функцией clone_node. Следующий код копирует элементы из корня первого документа в корень второго.

<?
$root1 = $dom1->document_element();
$child = $root1->child_nodes();

$root2 = $dom2->document_element();

for (
$i = 0; $i < sizeof($child); $i++)
       
$root2->append_child($child[$i]->clone_node());

Создание новых узлов в документе


Вы заметили, что здесь пишется то "элемент", то "узел". Надеюсь, из схемы наследования классов (см. выше) вам стало понятно, что элемент — это тег, а узел — это более общее понятие, включающее в себя всё на свете. Стараюсь употреблять эти слова в нужных местах, чтобы не было двусмыслия.

Любой узел вставляетс в документ в две операции. Первая — создание узла. Узел должен быть создан внутри того документа, в который он будет вставлен. Затем узел добавляется как дочерний к какому-либо из узлов документа. Для атрибутов, которые, по-хорошему, тоже узлы есть более удобная конструкция.

В документации по php, которую я скачивал недавно, есть список функций, которые были в предыдущих версиях, но не соответствовали спецификации DOM, и описания их работы. Их можно изучать, но применять не рекомендуется. С новыми версиями поведение некоторых конструкций и так менялось, поэтому полагаться на то, что приговорено к отмене, не стоит.

<?

/* Корневой элемент добавляется так же, как и другие узлы. */
$dom3 = domxml_new_doc();

/* Функция create_element создаёт узел типа элемент */
$root3_new = $dom3->create_element(root);

/* Теперь созданный элемент добавляется к документу. На самом деле, ничто не
    мешает отправить результат функции create_element в документ напрямую, а
    не через переменную $root3_new. */
$root3 = $dom3->append_child($root3_new);

$title = $root3->append_child($dom3->create_element(title));

/* Функция create_text_node создаёт текстовый узел. Его добавим как содержимое
    элемента title. Сохранять добавленный элемент в переменную необязательно -
    только если вы хотите с ним после добавления работать. */
$title->append_child($dom3->create_text_node(Создание новых узлов в документе));

Аналогично создаются и вставляются в документ узлы других типов.
Изменение узлов

Формально, таких методов... не предусмотрено. У атрибутов метод, изменяющий содержимое, есть. Есть элементы, в которых нет элементов дочерних, а есть только секции CDATA, текст с сущностями, либо комментарий. Изменять таковые можно путём удаления существующих узлов и вставки новых. Для элементов, имеющих дочерние вперемешку с текстовыми, метод редактирования был бы вообще нонсенсом.

Атрибуты создаются и изменяются через методы объектов элементов, в которых эти атрибуты содержатся. По спецификации они так же должны создаваться и добавляться в элементы через функции create_attribute и append_child, но это всё ещё не реализовано в PHP 4.3.1 (4.3.2).

<?
// Можно установить значение атрибута через объект его элемента
$root3->set_attribute(language, Russian);

// Так написано в документации, но не работает.
$root2->append_child($dom2->create_attribute(language, Russian));
?>

Объяснение, почему не работает — "не сделано пока что". Заодно предлагается пользоваться последней версией из CVS — вот не было печали; понятно, конечно, что DOM XML — это уже не для средних умов, но чтобы его нужно было добывать вот так — увольте. Так же предлагается использовать функцию set_attribute_node. В некоторых случаях это вызовет неудобство, когда, например, тип вставляемого в элемент узла заранее неизвестен — то ли будет сделан текст, то ли атрибут, и надо бы использовать одну функцию, а пока так нельзя, пришлось бы делать конструкцию if-else.

Замена одного текстового узла — это удаление существующего и вставка нового. Если нет уверенности, что в элементе только текстовый узел и нет других, можно клонировать элемент, вставить его в своего родителя и потом удалить исходный. Получится "чистый" элемент без дочерних, правда атрибуты при этом не скопируются.

<?
// $target - переменная с изменяемым элементом

// Получаем родительский узел.
$parent = $target->parent_node();

// Вставляем в него клон нужного нам узла.
$new_target = $parent->append_child($target->clone_node(false));

// Удаляем старый элемент.
$parent->remove_child($target);

// Вставляем в новый элемент нужный текст.
$new_target->append_child($dom->create_text_node(iconv(windows-1251,
   
UTF-8, Замена  узла - это удаление существующего и вставка нового.)));

С изменением текстовых узлов или секций CDATA в сложной комбинации элементов тоже несложно: получаем нужный объект, добавляем перед ним новый узел, а старый удаляем.

<?
$new_node = $target_node->insert_before($dom->create_text_node(iconv(windows-1251,
   
UTF-8,
   
Замена узла - это удаление существующего и вставка нового.)),
   
$target_node);

$parent = $target_node->parent_node();
$parent->remove_child($target_node);

2 последних строки можно было заменить одной — $target_node->unlink_node(), но, поскольку эта функция не соответствует стандарту, она может быть удалена и, соответственно, в примерах её лучше не использовать.
XSL-Трансформации в модуле DOM XML

XSLT — это тоже XML-документ. Он читается из файла (строки) — точно так же, как создаётся объект документа — или создаётся из объекта XML-документа. Затем вызывается метод process с объектом трансформируемого документа в качестве аргумента, и на выходе получается объект XML-документа.

<?
$xslt = domxml_xslt_stylesheet_doc(c:/xml/custom.xslt);
$dom = domxml_open_file(c:/xml/existing_file.xml);

$final = $xslt->process($dom);

print(
$final->dump_mem());

Заключение

Объектный подход к документу — это шаг вперед, наше светлое будущее. Модуль DOM XML предоставляет программный интерфейс с такими возможностями, каких не сделать на SAX-парсере в php-скрипте. Он устраняет неопределенности, связанные с трактовкой символов в сделанном вами XML-документе при его разборе XSLT-процессором или иным обработчиком. К примеру, проблемы с вставкой текста в элементы документа в DOM XML не существует, тогда как при работе с текстом документа нужно проверять и фильтровать служебные символы. Текст в DOM-объекте — это текст, а вот если его просто вставить в строку документа, где символы < и > превратятся в теги, а сущности, если не объявлены, могут вызвать ошибку.

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

Контакты
Редакция:
[0.001]