Mendapatkan elemen DOM dengan nama kelas

Jawaban:

154

Pembaruan: versi Xpath dari *[@class~='my-class']pemilih css

Jadi setelah komentar saya di bawah ini sebagai tanggapan atas komentar hakre, saya penasaran dan melihat kode di belakang Zend_Dom_Query. Sepertinya pemilih di atas dikompilasi ke xpath berikut (belum diuji):

[contains(concat(' ', normalize-space(@class), ' '), ' my-class ')]

jadi phpnya adalah:

$dom = new DomDocument();
$dom->load($filePath);
$finder = new DomXPath($dom);
$classname="my-class";
$nodes = $finder->query("//*[contains(concat(' ', normalize-space(@class), ' '), ' $classname ')]");

Pada dasarnya, semua yang kami lakukan di sini adalah menormalkan classatribut sehingga bahkan satu kelas pun dibatasi oleh spasi, dan daftar kelas lengkap dibatasi dalam spasi. Kemudian tambahkan kelas yang kita cari dengan spasi. Dengan cara ini kami secara efektif mencari dan menemukan hanya contoh my-class.


Gunakan pemilih xpath?

$dom = new DomDocument();
$dom->load($filePath);
$finder = new DomXPath($dom);
$classname="my-class";
$nodes = $finder->query("//*[contains(@class, '$classname')]");

Jika hanya satu jenis elemen Anda dapat mengganti *dengan tagname tertentu.

Jika Anda perlu melakukan banyak hal ini dengan pemilih yang sangat kompleks, saya akan merekomendasikan Zend_Dom_Queryyang mendukung sintaks pemilih CSS (a la jQuery):

$finder = new Zend_Dom_Query($html);
$classname = 'my-class';
$nodes = $finder->query("*[class~=\"$classname\"]");
prodigitalson
sumber
menemukan kelasnya my-class2juga, tapi cukup manis. Adakah cara untuk hanya memilih yang pertama dari semua elemen?
hakre
Saya tidak berpikir Anda bisa tanpa xpath2 ... Namun contoh untuk Zend_Dom_Query melakukan hal itu. JIKA Anda tidak ingin menggunakan compkenet itu dalam proyek Anda, maka Anda mungkin ingin melihat bagaimana mereka menerjemahkan pemilih css itu ke xpath. Mungkin DomXPath mendukung xpath 2.0 - saya tidak yakin tentang itu.
ajaib
1
karena classdapat memiliki lebih dari satu kelas misalnya: <a class="my-link link-button nav-item">.
ajaib
2
@prodigitalson: Ini salah karena tidak mencerminkan spasi, coba //*[contains(concat(' ', normalize-space(@class), ' '), ' classname ')](Sangat informatif: Pemilih CSS dan Ekspresi XPath ).
hakre
1
@babonk: ya, Anda perlu menggunakan containskombinasi dengan concat... kami hanya membahas rincian pengisian spasi di kedua sisi kelas yang Anda cari atau hanya mengisi satu sisi. Keduanya harus bekerja.
ajaib
20

Jika Anda ingin mendapatkan innerhtml kelas tanpa zend, Anda dapat menggunakan ini:

$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;
Tschallacka
sumber
2
Titik koma hilang untuk garis$classname = 'main-article'
Kamil
12

Saya pikir cara yang diterima lebih baik, tapi saya rasa ini mungkin berhasil juga

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;
}
dav
sumber
2
Dimana contoh untuk ini? Itu akan menyenangkan.
robue-a7119895
Itu hebat. Saya mendapat elemen dengan kelas. Sekarang saya ingin mengedit konten elemen, seperti menambahkan anak ke elemen yang berisi kelas. Bagaimana cara menambahkan anak dan membuat ulang seluruh HTML? Tolong bantu. Inilah yang telah saya lakukan. $classResult = getElementByClass($dom, 'div', 'm-signature-pad'); $classResult->nodeValue = ''; $enode = $dom->createElement('img'); $enode->setAttribute('src', $signatureImage); $classResult->appendChild($enode);
Keyur
1
untuk modifikasi dom oleh php saya pikir lebih baik untuk penggunaan phpquery github.com/punkave/phpQuery
dav
7

Ada juga pendekatan lain tanpa menggunakan DomXPathatau Zend_Dom_Query.

Berdasarkan fungsi asli dav, saya menulis fungsi berikut yang mengembalikan semua anak dari node induk yang tag dan kelasnya cocok dengan parameter.

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

misalkan Anda memiliki variabel $htmlHTML berikut:

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

penggunaan getElementsByClasssesederhana:

$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".
oabarca
sumber
6

DOMDocument lambat untuk mengetik dan phpQuery memiliki masalah kebocoran memori yang buruk. Saya akhirnya menggunakan:

https://github.com/wasinger/htmlpagedom

Untuk memilih kelas:

include 'includes/simple_html_dom.php';

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

Saya harap ini membantu orang lain juga

iautomation
sumber