Я использую PHP DOM, и я пытаюсь получить элемент внутри DOM node, который имеет заданное имя класса. Какой лучший способ получить этот подэлемент?
Обновление: Я закончил использование Mechanize
для PHP, с которым было гораздо легче работать.
Я использую PHP DOM, и я пытаюсь получить элемент внутри DOM node, который имеет заданное имя класса. Какой лучший способ получить этот подэлемент?
Обновление: Я закончил использование Mechanize
для PHP, с которым было гораздо легче работать.
Обновление: версия Xpath *[@class~='my-class']
селектор css
Итак, после моего комментария ниже в ответ на комментарий hakre мне стало любопытно и заглянул в код за Zend_Dom_Query
. Похоже, что вышеупомянутый селектор скомпилирован в следующий xpath (untested):
[contains(concat(' ', normalize-space(@class), ' '), ' my-class ')]
поэтому php будет:
$dom = new DomDocument();
$dom->load($filePath);
$finder = new DomXPath($dom);
$classname="my-class";
$nodes = $finder->query("//*[contains(concat(' ', normalize-space(@class), ' '), ' $classname ')]");
В основном все, что мы делаем здесь, нормализует атрибут class
, так что даже один класс ограничен пробелами, а полный список классов ограничен в пробелах. Затем добавьте класс, который мы ищем, с пробелом. Таким образом, мы эффективно ищем только экземпляры my-class
.
Использовать селектор xpath?
$dom = new DomDocument();
$dom->load($filePath);
$finder = new DomXPath($dom);
$classname="my-class";
$nodes = $finder->query("//*[contains(@class, '$classname')]");
Если это только один тип элемента, вы можете заменить *
на определенный тэг.
Если вам нужно много сделать с очень сложным селектором, я бы порекомендовал Zend_Dom_Query
, который поддерживает синтаксис селектора CSS (a la jQuery)
$finder = new Zend_Dom_Query($html);
$classname = 'my-class';
$nodes = $finder->query("*[class~=\"$classname\"]");
Если вы хотите получить innerhtml класса без zend, вы можете использовать это:
$dom = new DomDocument();
$dom->load($filePath);
$classname = 'main-article';
$finder = new DomXPath($dom);
$nodes = $finder->query("//*[contains(concat(' ', normalize-space(@class), ' '), ' $classname ')]");
$tmp_dom = new DOMDocument();
foreach ($nodes as $node)
{
$tmp_dom->appendChild($tmp_dom->importNode($node,true));
}
$innerHTML.=trim($tmp_dom->saveHTML());
echo $innerHTML;
Я думаю, что принятый способ лучше, но я думаю, что это тоже может работать
function getElementByClass(&$parentNode, $tagName, $className, $offset = 0) {
$response = false;
$childNodeList = $parentNode->getElementsByTagName($tagName);
$tagCount = 0;
for ($i = 0; $i < $childNodeList->length; $i++) {
$temp = $childNodeList->item($i);
if (stripos($temp->getAttribute('class'), $className) !== false) {
if ($tagCount == $offset) {
$response = $temp;
break;
}
$tagCount++;
}
}
return $response;
}
Существует также другой подход без использования DomXPath
или Zend_Dom_Query
.
На основе исходной функции dav я написал следующую функцию, которая возвращает все дочерние элементы родительского node, чей тег и класс соответствуют параметрам.
function getElementsByClass(&$parentNode, $tagName, $className) {
$nodes=array();
$childNodeList = $parentNode->getElementsByTagName($tagName);
for ($i = 0; $i < $childNodeList->length; $i++) {
$temp = $childNodeList->item($i);
if (stripos($temp->getAttribute('class'), $className) !== false) {
$nodes[]=$temp;
}
}
return $nodes;
}
предположим, что у вас есть переменная $html
следующего HTML:
<html>
<body>
<div id="content_node">
<p class="a">I am in the content node.</p>
<p class="a">I am in the content node.</p>
<p class="a">I am in the content node.</p>
</div>
<div id="footer_node">
<p class="a">I am in the footer node.</p>
</div>
</body>
</html>
использование getElementsByClass
так же просто, как:
$dom = new DOMDocument('1.0', 'utf-8');
$dom->loadHTML($html);
$content_node=$dom->getElementById("content_node");
$div_a_class_nodes=getElementsByClass($content_node, 'div', 'a');//will contain the three nodes under "content_node".
DOMDocument работает медленно, а phpQuery имеет проблемы с утечкой памяти. Я закончил использование:
https://github.com/wasinger/htmlpagedom
Чтобы выбрать класс:
include 'includes/simple_html_dom.php';
$doc = str_get_html($html);
$href = $doc->find('.lastPage')[0]->href;
Я надеюсь, что это поможет и кому-то другому.