Суббота, 20.06.2026, 01:22
Приветствую Вас Гость | RSS
Поиск по каталогу
Главная страница | Каталог статей | Регистрация | Вход

Информационные технологии
Форма входа
Меню сайта

Категории каталога
php [246]
perl [1]
perl
ASP [1]
AJAX [0]

Друзья сайта

Наш опрос
Оцените мой сайт
Всего ответов: 69

Начало » Статьи » Web программирование » php

Спецификация и функции DOM в PHP 1
[1 страница]
Введение: о спецификациях XML-технологий

Множество разных спецификаций вокруг XML в первую очередь направлены на то, чтобы упорядочить и привести к единому стандарту подходы к работе с данными в формате XML. На данный момент существуют XML + XLink + XSL + пространства имён + информационное множество + XML Linking + Модель XPointer + пространства имён XPointer + xptr() XPointer + XSLT + XPath + XSL FO + DOM + SAX + PI для связи с листом стилей + XML-схема + XQuery + Шифрование XML + Канонизация XML + XML-подпись + DOM уровня 2 + DOM уровня 3 (список взят из статьи "С днем рождения, XML!").
Введение: о спецификациях XML-технологий

Что такое DOM


Document Object Model (объектная модель документа). Объект в данном случае значит объект в программистском смысле — артефакт ООП и все прекрасное, за что мы его любим.

Взглянем на исходный код XML-документа:


xml version="1.0" encoding="windows-1251"?>

    XML: спецификация и функции DOM в PHP

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

    2003-05-12

   
       пример не well-formed разметки:

bla-bla

]]>
   

   


Основа идеологии XML в том, что документ — это набор узлов древовидной структуры данных. Данный документ можно представить в виде следующего дерева:

-o- Документ
|
+-o- Элемент root
|
+-o- Атрибут language
|
+-o- Элемент title
| |
| +-o- Текстовый узел ("XML: спецификация...")
|
+-o- Элемент text
| |
| +-o- Текстовый узел ("Множество...")
| |
| +-o- Элемент acronym
| | |
| | +-o- Текстовый узел ("XML")
| |
| +-o- Текстовый узел (" в первую очередь...")
| |
| +-o- Элемент b
| | |
| | +-o- Текстовый узел ("упорядочить")
| |
| +-o- Текстовый узел ("и привести...")
| |
| +-o- Элемент acronym
| | |
| | +-o- Текстовый узел ("XML")
| |
| +-o- Текстовый узел (".")
|
+-o- Элемент date
| |
| +-o- Текстовый узел ("2003-05-12")
|
+-o- Элемент raw-code
| |
| +-o- Секция CDATA ("
...")
|
+-o- Комментарий ("дописать...")

Знаком "-o-" на схеме обозначены узлы. Справа от них текст означает тип узла. Для текстовых узлов, секции CDATA и комментария добавлено содержимое — ради удобства ориентирования. На самом деле, по-хорошему, переносы строк между элементами являются текстовыми узлами, и их тоже можно было бы внести в схему.

Итак, разбираем схему. Всё, что есть в документе — узлы, и сам документ — тоже узел. Это значит, что есть класс объектов "узел", а остальные классы ("документ", "элемент", "текстовый узел", "CDATA", "комментарий") — дочерние от него и наследуют его свойства и методы. Какие свойства и методы должны содержаться в каких классах — описывается в спецификации DOM.

Если посмотреть в документацию по модулю DOM XML (тоже мне показатель :)), видно, что у всех этих разных узлов есть много общего — 28 методов у класса DomNode, а вместе с дочерними классами методов 62. Как можно догадаться, методы и свойства класса DomNode присутствуют и в других классах.

На сайте phpPatterns() недавно (9.4.3) появилась статья "Грубая схема модуля DOM XML в PHP" Гарри Фьюекса. Тем, кто по-английски умеет, можно прочитать первоисточник, остальным даю своё огрубление грубой схемы.

В статье приводится иллюстрация взаимоотношений классов модуля DOM XML. Вот дерево классов в моём исполнеии:

o- DomNode
|
+-o- DomAttribute
|
+-o- DomCData
| |
| +-o- DomComment
| |
| +-o- DomDTD
| |
| +-o- DomText
|
+-o- DomDocument
|
+-o- DomDocumentType
|
+-o- DomElement
|
+-o- DomEntity
|
+-o- DomEntityReference
|
+-o- DomProcessingInstruction

Далее приводятся замечания, что модуль DOM XML пока что не полностью соответствует спецификации (а "левыми" функциями уже каждый успел попользоваться, теперь во многих приложениях надо выковыривать их и переписывать код), что ещё много утечек памяти модуля будет исправлено в версии 4.3.2 (которая ещё не выпущена и находится в стадии релиз-кандидата). Но это мелочи жизни. Кто давно пользуется DOM XML, тому не привыкать, а если вы только начали знакомство с ним, то начнете использовать в реальных задачах уже тогда, когда он станет стабильным и будет соответствовать спецификации. В общем, продолжаем знакомство с DOM и модулем.

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

Поддержка кириллицы


Стандарт предусматривает работу с данными, перекодированными в UTF-8, поэтому все функции по вводу данных требуют, чтобы они были перекодированы, а на выходе выдают тоже UTF-8. Для перекодировки нужно пользоваться функцией iconv.

Измененная библиотека php_domxml с поддержкой русского языка доступна на сайте dan.phpclub.net. Она может создавать объект документа из файла или строки, в которых в открывающем теге стоит соответствующий атрибут:


xml version="1.0" encoding="windows-1251"?> русский текст

Функция dump_mem в ней тоже выдаёт текст в кодировке windows 1251, и на этом удобства заканчиваются - остальные данные нужно вводить в документ, перекодируя в UTF-8.
Создание документа

Объект документа можно создать из существующего файла или текстовой строки, либо абсолютно новый пустой документ.


$dom1 = domxml_open_file("c:/xml/existing_file.xml");
$dom2 = domxml_open_mem($string);
$dom3 = domxml_new_doc();
?>


Все эти функции при ошибке возвращают не объект, значение false, так что проверка результата операции достаточно простая.

По умолчанию при создании документа производится проверка его синтаксиса (well-form), но не допустимости (соответствие DTD-схеме или XML-схеме документа, validity). Чтобы проверять и на допустимость, нужно указать в функции создания документа (любая из трех приведенных выше) второй, недокументированный пока, параметр и в нём константу DOMXML_LOAD_VALIDATING:


$dom2 = domxml_open_mem($string, DOMXML_LOAD_VALIDATING);
?>


Получение объекта элемента


В памяти PHP после того, как документ был создан, хранятся все объекты элементов документа. Но в переменные скрипта они без специального вызова не записываются.

Корневой элемент документа можно получить, обратившись к объекту документа при помощи метода document_element. Функция возвращает объект класса DomElement, который можно использовать как аргумент другой функции, либо записать в переменную:


$root = $dom1->document_element();
?>


Аналогично можно получить любой узел из документа — при помощи методов объекта документа или объектов элементов.


// Массив дочерних элементов корневого
$root_child = $root->child_nodes();

for ($i = 0; $i < sizeof($root_child); $i++)
        print(
"$i. ". $root_child[$i]->node_type(). " ". $root_child[$i]->node_name().
            
"
"
);

// первый и последний дочерние элементы
$first_child = $root->first_child();
$last_child = $root->last_child();

print($first_child->node_name()." и ".$root_child[0]->node_name()." - одно и то же
"
);
print(
$last_child->node_name()." и ".$root_child[sizeof($root_child)-1]->node_name().
   
" - тоже совпадают
"
);

// элемент, следующий за первым
// previous_sibling работает точно так же
$second_child = $first_child->next_sibling();

print($second_child->node_name(). " ". $root_child[1]->node_name(). "
"
);


При разборе дочерних элементов важно следить за типами узлов, потому что переносы строк, которые ставятся для удобства чтения и редактирования, тоже становятся узлами документа и, соответственно, входят в массив дочерних элементов.


for ($i = 0; $i < sizeof($root_child); $i++)
        if (
$root_child[$i]->node_type() == XML_ELEMENT_NODE)
               
// Для иллюстрации здесь текст перекодируется, хотя для латиницы
                //это необязательно
               
$root_child[$i]->set_attribute("makes-sence", iconv("windows-1251",
                   
"UTF-8", "maybe"));
        else
                print(
"$i - элемент типа ". $root_child[$i]->node_type());


Впрочем иногда вообще нельзя быть уверенным в том, что получен объект узла, а не false или null. Тогда, если вызвать метод объекта, можно получить прямо в результирующий документ строчку с warning-ом. Чтобы этого избежать, можно проверять тип элемента функцией get_class.

А неуверенным в результате можно быть, например, когда вы достаёте нужный элемент из документа при помощи выражений XPath. Чтобы получить нужный элемент, не имеет смысла, конечно же, перебирать все элементы документа в его поисках. специально для этого есть выражения XPath, использующиеся в XSLT для адресации к узлам преобразуемого документа (атрибуты select, match).


/* Создание контекста XPath. Аргумент функции - объект документа, в котором выражения
    XPath будут выполняться. */
$context = xpath_new_context($dom1);

/* Выполнение выражения и запись результата в переменную result */
$result = xpath_eval($context, "/root/text/acronym");

var_dump($result);

/* Переменная $result - объект класса XPathObject, свойство nodeset - массив,
    содержащий     объекты полученных элементов. */
for ($i = 0; $i < sizeof($result->nodeset); $i++)
{
       
$text = $result->nodeset[$i]->first_child();
        print(
iconv("UTF-8", "windows-1251", $text->node_value()). "
"
);
}

/* Получение скалярного значения при помощи XPath (подсчёт числа всех элементов в
    документе кроме корневого) */
$result = xpath_eval($context, "count(/root//*)");

var_dump($result);
print(
"
{$result->value}"
);


Важно помнить про пространства имён XML, которые могут использоваться в документах. Если вы хотите выполнять выражения в документах, котоыре содержат элементы из своих пространств имён (например, XSLT-документы), вам нужно объявить это проистранство имён. Иначе нельзя будет указывать имена вида "xsl:template" в выражении.

Адрес (URI) пространства имён в аргументе функции обязательно должен совпадать с тем, что указан в документе, иначе XPath-парсер будет считать, что с одним и тем же префиксом xsl зарегистрированы два разных пространства имён.


$xslt = domxml_open_file("c:/xml/custom.xslt");
$context = xpath_new_context($xslt);

/* Регистрация пространства имён xsl в контексте XPath */
xpath_register_ns($context, "xsl", "http://www.w3.org/1999/XSL/Transform");

/* Подсчёт количества шаблонов в XSLT-стиле. */
$result = xpath_eval($context, "count(/xsl:stylesheet/xsl:template)");

print($result->value);


Итак, задача получения объекта нужного элемента разобрана. Теперь о том, что делать с ним.
Категория: php | Добавил: freeone (28.05.2007) | Автор: Дмитрий Лебедев
Просмотров: 625 | Комментарии: 1 | Рейтинг: 0.0 |

Всего комментариев: 0
Имя *:
Email *:
Код *:

Copyright Информационные технологии © 2006