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 );
// OR
$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 ) : DOMElement
public getElementsByTagName ( string $name ) : DOMNodeList
public 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);
}

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

%d такие блоггеры, как: