通过类名获取DOM元素


Answers:


154

更新:*[@class~='my-class']CSS选择器的Xpath版本

因此,在下面我回应hakre的评论之后,我感到好奇,并调查了后面的代码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选择器语法(类似于jQuery):

$finder = new Zend_Dom_Query($html);
$classname = 'my-class';
$nodes = $finder->query("*[class~=\"$classname\"]");

也可以找到课程my-class2,但是很不错。有什么办法只选择所有元素中的第一个?
hakre 2011年

我不认为您可以没有xpath2 ...但是Zend_Dom_Query的示例正是这样做的。如果您不想在项目中使用该compkenet,那么您可能想要查看它们如何将css选择器转换为xpath。也许DomXPath支持xpath 2.0-我不确定。
prodigitalson

1
因为class可以有多个类,例如:<a class="my-link link-button nav-item">
prodigitalson

2
@prodigitalson:这是不正确的,因为它不能反映空格,请尝试//*[contains(concat(' ', normalize-space(@class), ' '), ' classname ')](非常有用:CSS Selectors和XPath Expressions)。
hakre 2011年

1
@babonk:是的,您需要containsconcat... 结合使用,我们正在讨论在您要搜索的类的两侧填充空格或仅填充一侧的细节。无论哪种都可以。
prodigitalson 2011年

20

如果您希望在没有zend的情况下获取类的innerhtml,则可以使用以下代码:

$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;

2
该行缺少分号$classname = 'main-article'
Kamil

12

我认为可以接受的方式更好,但是我想这可能也会起作用

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;
}

2
这个例子在哪里?那就太好了。
robue-a7119895 2015年

那很棒。我在课堂上有了元素。现在,我想编辑元素的内容,例如将child追加到包含类的元素上。如何附加子项并重新创建整个HTML?请帮忙。这就是我所做的。$classResult = getElementByClass($dom, 'div', 'm-signature-pad'); $classResult->nodeValue = ''; $enode = $dom->createElement('img'); $enode->setAttribute('src', $signatureImage); $classResult->appendChild($enode);
Keyur

1
对于通过php进行的dom修改,我认为最好使用phpquery github.com/punkave/phpQuery
dav,

7

还有另一种不使用DomXPath或的方法Zend_Dom_Query

基于dav的原始函数,我编写了以下函数,该函数返回其tag和class与参数匹配的父节点的所有子节点。

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".

6

DOMDocument的输入速度很慢,而phpQuery有严重的内存泄漏问题。我最终使用:

https://github.com/wasinger/htmlpagedom

要选择一个班级:

include 'includes/simple_html_dom.php';

$doc = str_get_html($html);
$href = $doc->find('.lastPage')[0]->href;

我希望这也对其他人有帮助

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.