Я використовую PHP DOM і намагаюся отримати елемент у вузлі DOM, який має задане ім’я класу. Який найкращий спосіб отримати цей піделемент?
Оновлення: я закінчив використовувати Mechanize
для PHP, з яким було набагато простіше працювати.
Я використовую PHP DOM і намагаюся отримати елемент у вузлі DOM, який має задане ім’я класу. Який найкращий спосіб отримати цей піделемент?
Оновлення: я закінчив використовувати Mechanize
для PHP, з яким було набагато простіше працювати.
Відповіді:
Оновлення: версія Xpath *[@class~='my-class']
селектора css
Тож після мого коментаря нижче у відповідь на коментар хакре я зацікавився і заглянув у код позаду Zend_Dom_Query
. Схоже, що вищевказаний селектор компілюється на наступний xpath (неперевірений):
[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\"]");
my-class2
також, але досить солодкий. Будь-який спосіб вибрати лише перший з усіх елементів?
class
може мати більше одного класу, наприклад: <a class="my-link link-button nav-item">
.
//*[contains(concat(' ', normalize-space(@class), ' '), ' classname ')]
(Дуже інформативно: CSS Selectors And XPath Expressions ).
contains
в поєднанні з concat
... ми обговорюємо деталі прокладки пробілів з обох сторін класу, які ви шукаєте або лише додаєте одну сторону. І все, хоча працювати.
Якщо ви хочете отримати внутрішній код класу без зайвих зусиль, ви можете скористатися цим:
$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;
$classname = 'main-article'
Я вважаю, що прийнятий спосіб є кращим, але я думаю, що це може також працювати
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;
}
$classResult = getElementByClass($dom, 'div', 'm-signature-pad'); $classResult->nodeValue = ''; $enode = $dom->createElement('img'); $enode->setAttribute('src', $signatureImage); $classResult->appendChild($enode);
Існує також інший підхід без використання DomXPath
або Zend_Dom_Query
.
На основі початкової функції dav я написав наступну функцію, яка повертає всіх дітей батьківського вузла, тег та клас яких відповідають параметрам.
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;
Я сподіваюся, що це допомагає і комусь іншому