//! ищет дочерний DOM-элемент по тэгу, значению, тексту, аттрибутам /*! Аттрибуты $tagName, $tagValue, $innerText - представлены регулярными выражениями стиля PERL в ограничителях #...#. \param $domElement элемент типа DOMElement - узловой элемент, среди дочерних объектов которого ведется поиск. \param $tagName элемент типа string - название тэга; если $tag=false, то фильтрация по имени тэга не производится \param $tagValue возможное значение тэга (аттрибут value); может быть false. \param $innerText текст, входящий в текстовое представление элемента \param $attributes ассоциативный массив аттрибутов, по которым ведется фильтрация; значения выражены perl-regexp в regex-скобках |...| \return php-массив элементов типа DOMElement */ function dom_filter($domElement, $tagName, $tagValue, $innerText, $attributes) { $result = array();
$elements = $domElement->childNodes;
for($i=0; $i<$elements->length; $i++) { $el = $elements->item($i); $valid = true;
// проверка имени, значения и текстового содержания тэга if($tagName and !preg_opt($tagName, $el->nodeName)) $valid=false; if($tagValue and !preg_opt($tagValue, $el->nodeValue)) $valid=false; if($innerText and !preg_opt($innerText, $el->textContent)) $valid=false;
// проверка аттрибутов if(is_array($attributes)) { reset($attributes); while($valid and list($attr_name, $attr_value) = each($attributes)) { if(!preg_opt($attr_value, $el->getAttribute($attr_name))) { $valid = false; break; } } }
// если элемент удовлетворяет условиям, то добавить его в массив, если нет - искать в его дочерних элементах if($valid) { $result []= $el; } elseif($el->hasChildNodes()) { $subresult = dom_filter($el, $tagName, $tagValue, $innerText, $attributes); $result = array_merge($result, $subresult); } } return $result; }
//! Поиск элемента согласно заданному иерархическому шаблону. //! Функция рекурсивна; использует dom_filter(...) для начальной выборки.\n /*! Пример шаблона: \n <code><pre> $pattern = array( 'tag' => '=div', // корневой тег 'value' => '~value', // значение 'text' => '~inner_text_pattern', // шаблон текста, содержащегося в текстовом представлении тэга 'attr' => array( // различные свойства тэга 'class' => '=auto', 'href' => '~adsfsadf', 'sel' => true // вносить этот элемент в таблицу результатов ), 'sub' => array( // дочерние тэги array( 'tag' => '=a', 'text' => '!...', 'attr' => array('href' => '~/auto.ru/adv/.*'), 'optional' => true ), array( 'tag' => '=img', 'attr' => array('src' => '=...'), 'sel' => true ) ) ); </pre></code>
<TABLE><CAPTION>Значимые элементы шаблона</CAPTION> <TR><TD> tag <TD> имя тэга <TR><TD> value <TD> значение тэга <TR><TD> text <TD> текстовое представление <TR><TD> attr <TD> массив шаблонов аттрибутов тэга <TR><TD> sel <TD> булево значение, будет ли элемент, соответствующий шаблону внесен в итоговый массив <TR><TD> optional <TD> обязательно ли наличие элемента в шаблоне (если optional=true, значит необязательно) <TR><TD> sub <TD> массив вложенных шаблонов такого же формата </TABLE>
<TABLE><CAPTION>отношения</CAPTION> <TR><TD>=<TD>равенство строке <TR><TD>-<TD>неравенство строке <TR><TD>~<TD>удовлетворение регулярному выражению в стиле PERL в ограничителях #...# (вхождения '#' в текст автоматически заменяется) <TR><TD>*<TD>удовлетворение регулярному выражению вне зависимости от регистра <TR><TD>!<TD>не удовлетворение регулярному выражению PERL <TR><TD>^<TD>не удовлетворение регулярному выражению вне зависимости от регистра </TABLE>
\param $element элемент DOMElement, в котором производится поиск \param $pat шаблон фильтрации. \return php-массив объектов типа DOMElement, удовлетворяющих шаблону */ function dom_struct($element, $pat) { $result = array();
// первичный отбор элементов $elements = dom_filter($element, $pat['tag'], $pat['value'], $pat['text'], $pat['attr']);
// если результат поиска пуст if(!is_array($elements) or count($elements)==0) { return $result; } // если нет вложенного поиска, то закончить и вернуть найденное if(!is_array($pat['sub']) or count($pat['sub'])==0) { if($pat['sel']) return $elements; else return array(true); }
// перебор найденных элементов для рекурсивного поиска for(reset($elements); $el=current($elements); next($elements)) { $tempres = array(); // временный результат, который будет отброшен, если не будет найден хотя бы один вложенный шаблон $valid = true; // проверка вложенных шаблонов for($j=0; $j<count($pat['sub']); $j++) { $r = dom_struct($el, $pat['sub'][$j]); if(is_array($r) and count($r)>0) { if($pat['sel']) $tempres []= $el; if(!($r[0] === true)) $tempres = array_merge($tempres, $r); } elseif(!$pat['optional']) { $valid = false; break; } } if($valid) $result = array_merge($result, $tempres); } return $result; } |