DOMDocument

DOMDocument — класс для работы с XML-документами. Данный инструмент удобно использовать, когда вам надо парсить xml/html-документы.

Простой пример использования класса DOMDocument:

$dom = new DOMDocument();$dom->loadHTML( $html);$dom->saveHTML();

Рассмотрим основные ошибки и сложности с которыми можно столкнуться:

  • Кодировка
  • Невалидный документ
  • Выбор елементов
  • Удаление елементов

Кодировка

Для начала документ необходимо загрузить с корректной кодировка. В случае, если мы работает не со всей страницей, а например с каким-то блоком, то элементов head и body нет и соответственно тега для указания кодировка тоже нет. DOMDocument доставит теги head и body самостоятельно, но кодировку нам необходимо будет указать самостоятельно:

$dom->loadHTML( '<meta charset="utf-8">'. $html);// или$dom->loadHTML( '<?xml encoding="utf-8"?>'. $html);

Так же документ надо правильно сохранить:

$dom->saveHTML( $dom->documentElement);

Иногда нам необходимо на выходе приобрести конкретный елемент, а не весь документ, то мы так же можем это сделать:

$dom->saveHTML( $dom->getElementById( 'element'));

Если необходимо приобрести всю контентную часть тогда сохранение будет выглядеть примерно так:

$html = '';$body_items = $dom->getElementsByTagName( 'body')->item( 0)->childNodes;foreach( $body_items as $node) {$html.= $dom->saveHTML( $node);}

Иногда приходится работать с невалидными документами. При загрузке DOMDocument исправит разметку. Можно легко убрать warnings при помощи следующей конструкции:

libxml_use_internal_errors( true);$dom->loadHTML( $html);libxml_clear_errors();

Выборки

Простые выборки можно сделать при помощи способов DOMDocument:

public getElementById( string $elementId): DOMElementpublic getElementsByTagName( string $name): DOMNodeListpublic getElementsByTagNameNS( string $namespaceURI, string $localName): DOMNodeList

Любые выборки можно легко сделать при помощи объекта класса DOMXPath, который реализовывает спецификацию XPath:

Селектор Действие
/h1 Выбрать все теги h1 в корне документа
body/h1 Выбрать все теги h1 которые внутри body
body//h1 Выбрать все теги h1 которые внутри body не зависимо от вложенности
//h1 Выбрать все теги h1
//h1[@title] Выбрать все теги h1 с атрибутом title
//h1[@title=»Name title»] Выбрать все теги h1 с атрибутом title=»Name title»
//h1[span] Выбрать все теги h1 с тегом span внутри
//h1[span=»Some text»] Выбрать все теги h1 с тегом <span>Some text</span> внутри
//h1[span>40] Выбрать все теги h1 с тегом span у которого nodeValue > 40
* Выбрать все элементы
//@* Выбрать все атрибуты
//h1/* Выбрать все дочерние элементы тега h1
//title[@*] Выбрать все элементы с атрибутов title
//h1 | //h2 Выбрать все элементы h1 и h2

XPath — не так прост, чем привычные всем CSS-селекторы, но XPath мощнее и может включать в себя возможности, операторы сравнении, поиск элемента с дочерним элементом и иное.

Примеры возможностей XPath:

  • contains()
  • text()
  • starts-with()
  • sum()
  • count()
//a[starts-with( @href, ‘#’)] Выбрать все теги a, у которых ссылка начинается с символа «#»

Проблема удаления

Если мы хотим удалить узел, то весь документ перестраивается. Следующий код отработает правильно только при первом удалении.

foreach( $elements as $element) { $element->parentNode->removeChild($href);}

Решением будет перебор елементов начиная с конца массива:

for( $i = $elements->length; --$i >= 0; ) { $element = $elements->item($i); $element->parentNode->removeChild($href);}

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *