Поиск по блогу

понедельник, 19 июля 2010 г.

Навигация по DOM-дереву в html

Сегодня статья опять будет про PHP Simple Html DOM Parser. Даже несмотря на то, что некоторым читателям эта тема могла хорошенько поднадоесть. :) Просто хочется собрать на блоге достаточное количество материала, к которому можно было бы отсылать вопрошающих по емэйлу.

Итак, навигация по DOM-дереву. Прямо здесь. Прямо сейчас. На примерах. (Так как теоретически она и так описана в инструкции к библиотеке).

Если вы читаете эту статью, то вам уже известно, что такое DOM-структура, древовидное представление данных, узлы дерева, родитель, потомок и т.д.. Структуру html-документа в виде дерева можно наглядно посмотреть в Firebug-е.
Древовидная структура html-документа в firebug
Там же есть закладка DOM, с содержимым которой советую ознакомиться новичкам. Из структуры, которая там раскрывается, вы наглядно увидите результаты обращения к дочерним элементам, отдельным узлам, свойствам, атрибутам и т.д..
DOM-структура html-документа в firebug
Но вернемся к PHP Simple Html DOM Parser.

Для примера возьмем простенький html-код с таблицей из трех столбцов и трех строк.
<html>
<body>
<table sellpadding="0" cellspacing="0" width="100%">
<tr>
<td>1.1</td>
<td>1.2</td>
<td>1.3</td>
</tr>
<tr>
<td>2.1</td>
<td>2.2</td>
<td>2.3</td>
</tr>
<tr>
<td>3.1</td>
<td>3.2</td>
<td>3.3</td>
</tr>
</table>
</body>
</html>


Для тех, кто не любит читать на английском, привожу перевод описания функций:
mixed $e->children ( [int $index] ) - возвращает N-ого потомка, если $index указан, или массив всех потомков, если индекс не указан.
element $e->parent () - возвращает родителя элемента.
element $e->first_child () - возвращает первого потомка элемента или null, если потомков нет.
element $e->last_child () - возвращает последнего потомка элемента или null, если потомков нет.
element $e->next_sibling () - возвращает следующего потомка элемента или null, если таковой не найден.
element $e->prev_sibling () - возвращает предыдущего потомка элемента или null, если таковой не найден.


children(N) эквивалентно childNodes(N).

Следующий код пройдет позволит обойти все ряды и столбцы таблицы:

$html = str_get_html($html_str);
foreach ($html->find("table", 0)->children() as $tr) {
foreach ($tr->children() as $td) {
echo $td->innertext.';&nbsp;';
}
echo '<br>';
}


Если в переменной $html_str приведенный выше код таблицы, то результат будет:
1.1; 1.2; 1.3;
2.1; 2.2; 2.3;
3.1; 3.2; 3.3;

Тут, думаю, все понятно, проблем возникнуть не должно. Просто проходимся по массивам.
Следующий способ навигации - с помощью next_sibling. next_sibling и prev_sibling используют для навигации по элементам, находящимся на одном уровне (т.е. имеющих общего родителя). Для примера пройдемся по всем ячейкам первой строки таблицы. Код этой нехитрой операции будет выглядеть так:
$element = $html->find('table tr td',0);
while($element) {
echo $element->innertext.';&nbsp;';
$element = $element->next_sibling();
}

Результатом будет:
1.1; 1.2; 1.3;


Вот, в принципе, и все. Постаралась коротко и ясно, без всякой воды.
Удачных разработок!
___

Чтобы быть в курсе обновлений блога, можно подписаться на RSS.

Статьи схожей тематики:



8 комментариев:

  1. Спасибо за Ваши статьи! Очень много нового для себя подчерпнул!

    ОтветитьУдалить
  2. featzima, когда-нибудь напишу и про XPath. Тем у меня в блокноте много :), только вот свободного времени — не очень.

    ОтветитьУдалить
  3. И все же PHP Simple Html DOM Parser не всегда нормально разбирает html с ошибками (не смотря на то что про него пишут).
    А Firefox показывает не исходный текст страницы с ошибками, а тот , который перерабатывает сам браузер. Поэтому можно долго пыхтеть пытаясь найти причину неправильной навигации по DOM дереву в HTML.

    ОтветитьУдалить
  4. Дмитрий, да, это факт, на Firefox полагаться не стоит, надо проверять по исходному коду.
    По поводу "не всегда правильно разбирает html" — может быть, не исключено. Хотя лично я пока не сталкивалась, но письма об этом не раз получала. Проверить и своими глазами посмотреть пока некогда.

    ОтветитьУдалить
  5. Если html с ошибками, нужно делать тоже что и фаерфокс - пропустить его через tidy, соответственное расширение в php есть.

    ОтветитьУдалить
  6. Спасибо за отличный блог :)

    ОтветитьУдалить
  7. Во время работы с этим инструментом столкнулся с проблемой невозможности удалять узлы. Считаю это большим упущением, т.к. это очень частая задача. Т.к. класс не обновляется и не развивается уже больше двух лет, к автору не обращался и нашел ответ в интернете. Рунет ничего не подсказал, но у зарубежных коллег ответ нашелся. Действительно, в классе нет метода удаления узлов, но по следующей ссылке есть описание этого метода. Его можно добавить прямо в класс, либо объявить в классе-наследнике. Я вставил прямо в класс, т.к. проект заброшен и обновляться не будет.

    Ссылка: http://stackoverflow.com/questions/1956850/html-parsing-using-simple-html-dom-parser

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

    Надеюсь, кому-то поможет.

    ОтветитьУдалить

Комментарии модерируются, вопросы не по теме удаляются, троллинг тоже.

К сожалению, у меня нет столько свободного времени, чтобы отвечать на все частные вопросы, так что, может, свой вопрос лучше задать на каком-нибудь форуме?

Поделиться