Работа с dom php

Работа с dom php

Введение: о спецификациях 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 в том, что документ — это набор узлов древовидной структуры данных. Данный документ можно представить в виде следующего дерева:

-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. Она может создавать объект документа из файла или строки, в которых в открывающем теге стоит соответствующий атрибут:

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

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

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

Читайте также:  Vboxextpackregister returned verr version mismatch

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

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

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

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

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

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

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

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

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

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

Итак, задача получения объекта нужного элемента разобрана. Теперь о том, что делать с ним.

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

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

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

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

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

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

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

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

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

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

Читайте также:  Форматирование поврежденной sd карты

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

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

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

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

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

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

    Подборки, 27 октября 2015 в 19:07

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

В таких случаях перед программистом встает вопрос: какую из десятков библиотек выбрать? В этой статье мы постарались рассмотреть самые популярные варианты и выбрать из них лучший.

Регулярные выражения

Даже не смотря на то, что «регулярки» — это первое, что приходит на ум, использовать их для настоящих проектов не стоит.

Да, с простыми задачами регулярные выражения справляются лучше всех, но его использование значительно затрудняется, когда нужно спарсить большой и сложный кусок HTML-кода, который, к тому же, не всегда соответствует какому-то определенному шаблону и вообще может содержать синтаксические ошибки.

ZIP Service, Москва, можно удалённо, от 100 000 ₽

Вместо «допиливания» своего регулярного выражения при каждом малейшем изменении кода рекомендуем использовать инструменты ниже — это и проще, и удобнее, и надежнее.

XPath и DOM

DOM и XPath не являются библиотеками в привычном смысле этого слова, это стандартные модули, которые встроены в PHP начиная с пятой версии. Именно отсутствие необходимости использовать сторонние решения делает их одними из лучших инструментов для парсинга HTML страниц.

На первый взгляд может показаться, что низкий порог входа — это не о них, некоторые места и вправду являются весьма сложными. Но это только на первый взгляд: стоит только немного разобраться с синтаксисом и базовыми принципами, как XPath тут же станет для вас инструментом для парсинга номер один.

Вот, например, код с использованием DOM и XPath, который ищет в разметке все теги и модифицирует их атрибуты src :

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

Simple HTML DOM

Simple HTML DOM — PHP-библиотека, позволяющая парсить HTML-код с помощью удобных jQuery-подобных селекторов.

Она лишена главного недостатка XPath — библиотека умеет работать даже с невалидным HTML-кодом, что значительно упрощает работу. Вы также забудете о проблемах с кодировкой: все преобразования выполняются автоматически.

Как и JQuery, Simple HTML DOM умеет искать и фильтровать вложенные элементы, обращаться к их атрибутам и даже выбирать отдельные логические элементы кода, например, комментарии.

Читайте также:  C datetime to unix timestamp

В этом примере сначала подгружается, а потом модифицируется заранее заготовленный HTML-код: во второй строке происходит добавление атрибута class со значением bar первом попавшемуся элементу div , а в следующей строке мы заменяем текст элемента с > на foo .

Несмотря на не самую высокую производительность, по сравнению с другими вариантами, Simple HTML DOM имеет самое большое русскоязычное комьюнити и наибольшую распространенность в рунете — для новичков это делает написание кода с её использованием значительно проще.

phpQuery

Как и Simple HTML DOM, phpQuery является PHP вариантом JQuery, но на этот раз более похожим на своего «старшего javascript-брата».

Портировано почти всё, что есть в JS-фреймворке: поддержка селекторов, атрибутов, манипуляций, обхода, плагинов, событий (в том числе имитации кликов и т.д.) и даже AJAX. Использовать можно как через PHP, так и через командную строку в виде отдельного приложения.

Более того, согласно нашим бенчмаркам, phpQuery оказался в 8 (!) раз быстрее Simple HTML DOM.

Вот небольшой пример на phpQuery, в котором происходит обработка заранее выбранных элементов списка ( li ):

Подробную документацию и больше примеров найдете на официальной странице в Google Code.

htmlSQL

htmlSQL — экспериментальная PHP библиотека, позволяющая манипулировать HTML-разметкой посредством SQL-подобных запросов.

Простейший пример, извлекающий атрибуты href и title всех ссылок (элементы a ) с классом list :

Как и с обычными mysql_ функциями, воспользовавшись методами fetch_array() или fetch_objects(), мы можем получить результат выполнения данного запроса в виде привычного ассоциативного массива или объекта.

Стоит также упомянуть о высоком быстродействии htmlSQL: часто она справляется в несколько раз быстрее phpQuery или того же Simple HTML DOM.

Тем не менее, для сложных задач вам может не хватить функциональности, а разработка библиотеки давно прекращена. Но даже несмотря на это, она всё ещё представляет интерес для веб-разработчиков: в ряде случаев значительно удобнее использовать язык SQL вместо CSS-селекторов. Особенно когда вы не знаете, что такое CSS-селекторы 😉

Вывод

В своем мини-исследовании мы пришли к выводу, что в большинстве случаев для парсинга лучше использовать библиотеку phpQuery: она быстрая, функциональная и современная.

С другой стороны, для совсем простых задач логично было бы использовать стандартные модули PHP, такие как XPath, DOM или, на крайний случай, регулярные выражения.

Что-то ещё?

Для PHP существуют ещё десятки разнообразных библиотек и инструментов для парсинга, но в этой статье мы рассмотрели только самые интересные, функциональные и производительные.

Подробнее о других способах парсинга средствами PHP можно прочитать в соответствующей теме на StackOverflow.

Если вы не используете PHP, то можете ознакомится с кратким списком похожих инструментов для других языков программирования:

(Document Object Model)

Наиболее широко применяемы XML-расширением на сегодняшний день является DOM и simpleXML, оба из них были добавлены в 5 версии PHP. Кроме данных XML-расширений также применяются XML (XML-парсер) и DOMXML, однако эти технологии считаются устаревшими.

Работа с DOM осуществляется в объектно-ориентированном стиле. Для начала работы с ним нужно создать объект domDocument. На практике это выглядит примерно так:

$dom_xml = new DomDocument;

При создании нового объекта domDocument вызывается конструктор DOMDocument=>__construct, имеющий два необязательных аргумента, которые указывают на версию документа и его кодировку

_ _construct ([string version [, string encoding]])

После создания нового объекта domDocument необходимо загрузить данные. Осуществляется это при помощи методов DOMDocument->load() и DOMDocuтeпt->loadXML() , в первом случае данные загружаются из файла, а во втором из строки. На практике это выглядит примерно так:

//Загрузка данных из файла с явным указанием экземпляра класса:

$dom_xml = new DomDocument;
$dom_xml->load(‘
file.xml‘);

//Загрузка данных из файла без явного указания экземпляра класса:

$dom_xml=DomDocument:: load(‘file.xml’);

//Загрузка данных из строки с явным указанием экземпляра класса:

$dom_xml = new DomDocument;
$dom_xml->loadXML(‘ volvo ‘);

//Загрузка данных из строки без явного указания экземпляра класса:

$dom_xml = DomDocument::lоаdХМL(‘ volvo ‘);

Если загрузка данных прошла успешно, то будет возвращено TRUE, если нет, то FALSE

После того как данные загружены чаще всего осуществляется разбор их. Осуществить это можно при помощи метода DomDocument->getElementsByTagName(). Этот метод возвращает коллекцию объектов DOMNode.

$dom_xml= new DomDocument();
$dom_xml->loadXML(‘ volvo Lada ‘);
//записываем название модели в переменную

Foreach ($mod as $element) <
echo $element->nodeValue." ".$element->nodeName." ".’
‘;
>
?>

volvo model
Lada model

Основные свойства объекта DOMNode

nodeName nodeValue Возвращает значения узлов childNodes Возвращает дочерние узлы для текущего узла firstChild Возвращает верхний (первый) дочерний узел lastChild Возвращает последний дочерний узел

Основные методы объекта DOMNode

removeChild() hasChildNodes() Осуществляет проверку на дочерние узлы appendChild() Добавляет элемент replaceChild() Замещает узел hasAttributes() Проверка атрибутов

Примеры работы с DOM можно увидеть на следующих страницах:

Ссылка на основную публикацию
Adblock detector