Таким образом, я в ситуации, когда я очищаю веб-сайт с PHP, и мне нужно иметь возможность получить узел на основе его класса css. Мне нужно получить тег ul, который не имеет атрибута id, но имеет класс css. Затем мне нужно получить только теги li, которые содержат определенные теги привязки, а не все теги li.
Я просмотрел DOMDocument, Zend_Dom, и у меня нет обоих требований, выбора класса и обхода объекта (в частности, восхождение к родителям).
Вы можете использовать querypath, и тогда что-то вроде этого может работать:
htmlqp($html)->find("ul.class")->not("#id") ->find('li a[href*="specific"]')->parent() // then foreach over it or use ->writeHTML() for extraction
См. http://api.querypath.org/docs/class_query_path.html для API.
(Перемещение намного проще, если вы не используете Fiddly DOMDocument.)
Вы можете сделать это с помощью DOMDocument и DOMXPath . Выбор по классу в XPath – это боль, но это можно сделать.
Вот пример (и полностью действительный!) HTML:
$html = <<<EOT <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <title>Document Title</title> <ul id="myid"><li>myid-listitem1</ul> <ul class="foo theclass "><li>list2-item1<li>list2-item2</ul> <ul id="myid2" class="foo
theclass bar"><li>list3-item1<li>list3-item2</ul> EOT ; $doc = new DOMDocument(); $doc->loadHTML($html); $xp = new DOMXPath($doc); $nodes = $xp->query("/html/body//ul[not(@id) and contains(concat(' ',normalize-space(@class),' '), ' theclass ')]"); var_dump($nodes->length);
Если вы используете PHP 5.3, вы можете упростить это, зарегистрировав функцию XPath в php. (Обратите внимание, что вы можете регистрировать функции для использования в выражениях XPath с помощью XSLTProcessor
начиная с PHP 5.1, но не напрямую для DOMXPath
.)
function hasToken($nodearray, $token) { foreach ($nodearray as $node) { if ($node->nodeValue===null or !hasTokenS($node->nodeValue, $token)) { return False; } } return True; // I could even return nodes or document fragments if I wanted! } function hasTokenS($str, $token) { $str = trim($str, "\r\n\t "); $tokens = preg_split('/[\r\n\t ]+/', $str); return in_array($token, $tokens); } $xp->registerNamespace('php', 'http://php.net/xpath'); $xp->registerPhpFunctions(array('hasToken', 'hasTokenS')); // These two are equivalent: $nodes1 = $xp->query("/html/body//ul[not(@id) and php:function('hasToken', @class, 'theclass')]"); $nodes2 = $xp->query("/html/body//ul[not(@id) and php:functionString('hasTokenS', @class, 'theclass')]"); var_dump($nodes1->length); var_dump($nodes1->item(0)); var_dump($nodes2->length); var_dump($nodes2->item(0));
Если DOMDocument
просто не DOMDocument
ваш HTML очень хорошо, вы можете использовать парсер html5lib , который вернет DOMDocument:
require_once('lib/HTML5/Parser.php'); // or where-ever you put it $dom = HTML5_Parser::parse($html); // $dom is a plain DOMDocument object, created according to html5 parsing rules
Мне повезло: http://simplehtmldom.sourceforge.net/