Итак, навигация по DOM-дереву. Прямо здесь. Прямо сейчас. На примерах. (Так как теоретически она и так описана в инструкции к библиотеке).
Если вы читаете эту статью, то вам уже известно, что такое DOM-структура, древовидное представление данных, узлы дерева, родитель, потомок и т.д.. Структуру html-документа в виде дерева можно наглядно посмотреть в Firebug-е.
Там же есть закладка DOM, с содержимым которой советую ознакомиться новичкам. Из структуры, которая там раскрывается, вы наглядно увидите результаты обращения к дочерним элементам, отдельным узлам, свойствам, атрибутам и т.д..
Но вернемся к 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.'; ';
}
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.'; ';
$element = $element->next_sibling();
}
Результатом будет:
1.1; 1.2; 1.3;
Вот, в принципе, и все. Постаралась коротко и ясно, без всякой воды.
Удачных разработок!
___
Чтобы быть в курсе обновлений блога, можно подписаться на RSS.
И не слова про XPath =$)
ОтветитьУдалитьСпасибо за Ваши статьи! Очень много нового для себя подчерпнул!
ОтветитьУдалитьfeatzima, когда-нибудь напишу и про XPath. Тем у меня в блокноте много :), только вот свободного времени — не очень.
ОтветитьУдалитьИ все же PHP Simple Html DOM Parser не всегда нормально разбирает html с ошибками (не смотря на то что про него пишут).
ОтветитьУдалитьА Firefox показывает не исходный текст страницы с ошибками, а тот , который перерабатывает сам браузер. Поэтому можно долго пыхтеть пытаясь найти причину неправильной навигации по DOM дереву в HTML.
Дмитрий, да, это факт, на Firefox полагаться не стоит, надо проверять по исходному коду.
ОтветитьУдалитьПо поводу "не всегда правильно разбирает html" — может быть, не исключено. Хотя лично я пока не сталкивалась, но письма об этом не раз получала. Проверить и своими глазами посмотреть пока некогда.
Если html с ошибками, нужно делать тоже что и фаерфокс - пропустить его через tidy, соответственное расширение в php есть.
ОтветитьУдалитьСпасибо за отличный блог :)
ОтветитьУдалитьВо время работы с этим инструментом столкнулся с проблемой невозможности удалять узлы. Считаю это большим упущением, т.к. это очень частая задача. Т.к. класс не обновляется и не развивается уже больше двух лет, к автору не обращался и нашел ответ в интернете. Рунет ничего не подсказал, но у зарубежных коллег ответ нашелся. Действительно, в классе нет метода удаления узлов, но по следующей ссылке есть описание этого метода. Его можно добавить прямо в класс, либо объявить в классе-наследнике. Я вставил прямо в класс, т.к. проект заброшен и обновляться не будет.
ОтветитьУдалитьСсылка: http://stackoverflow.com/questions/1956850/html-parsing-using-simple-html-dom-parser
Функция в первом ответе. Можно удалять все узлы по селектору, можно задать лимит. Причем лимит может быть отрицательным и тогда отсчет будет от последнего элемента.
Надеюсь, кому-то поможет.