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\"]");

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;

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

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

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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.