DOM öğelerini sınıf adına göre alma


Yanıtlar:


154

Güncelleme: *[@class~='my-class']css seçicinin Xpath sürümü

Hakre'nin yorumuna cevaben aşağıdaki yorumumdan sonra, merak ettim ve arkasındaki kodu inceledim Zend_Dom_Query. Yukarıdaki seçici aşağıdaki xpath için derlenmiş gibi görünüyor (test edilmemiş):

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

yani php şöyle olacaktır:

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

Temel olarak, burada yaptığımız classtek şey, tek bir sınıf bile boşluklarla sınırlanacak ve tüm sınıf listesi boşluklarla sınırlanacak şekilde niteliği normalize etmektir . Ardından aradığımız sınıfı bir boşlukla ekleyin. Bu şekilde etkin bir şekilde sadece örneklerini arıyoruz ve buluyoruz my-class.


Bir xpath seçici mi kullanıyorsunuz?

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

Yalnızca tek tür bir öğe *ise, belirli bir etiket adı ile değiştirebilirsiniz .

Bunu çok karmaşık seçici ile yapmanız gerekiyorsa Zend_Dom_Query, CSS seçici sözdizimini (a la jQuery) destekleyen hangisini öneririm :

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

sınıfı my-class2da bulur , ancak oldukça tatlıdır. Tüm öğelerden yalnızca ilkini seçmenin bir yolu var mı?
hakre

Xpath2 olmadan yapabileceğinizi sanmıyorum ... Ancak Zend_Dom_Query örneği tam olarak bunu yapıyor. Projenizde bu compkenet'i kullanmak istemiyorsanız, o css seçiciyi xpath'e nasıl çevirdiklerini görmek isteyebilirsiniz. Belki DomXPath, xpath 2.0'ı destekliyor - bundan emin değilim.
prodigitalson

1
Çünkü classörneğin birden fazla sınıf sahip olabilir: <a class="my-link link-button nav-item">.
prodigitalson

2
@prodigitalson: Boşlukları yansıtmadığı için bu yanlıştır, deneyin //*[contains(concat(' ', normalize-space(@class), ' '), ' classname ')](Çok bilgilendirici: CSS Seçiciler ve XPath İfadeleri ).
hakre

1
@babonk: evet, kullanmak gerekir containsile birlikte concat... biz jsut için sınıf sen arama her iki tarafındaki boşluk doldurma veya sadece bir tarafını doldurma ettiği durumların görüşüyorlar. Her ikisi de çalışmalı.
prodigitalson

20

Sınıfın içhtml'sini zend olmadan almak isterseniz, bunu kullanabilirsiniz:

$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
Satır için eksik noktalı virgül$classname = 'main-article'
Kamil

12

Kabul edilen yolun daha iyi olduğunu düşünüyorum, ancak bu da işe yarayabilir

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
Bunun örneği nerede? Güzel olurdu.
robue-a7119895

Bu harika. Sınıfın elementini aldım. Şimdi, sınıfı içeren öğeye çocuk eklemek gibi öğenin içeriğini düzenlemek istiyorum. Çocuk nasıl eklenir ve tüm HTML nasıl yeniden oluşturulur? Lütfen yardım et. Yaptığım bu. $classResult = getElementByClass($dom, 'div', 'm-signature-pad'); $classResult->nodeValue = ''; $enode = $dom->createElement('img'); $enode->setAttribute('src', $signatureImage); $classResult->appendChild($enode);
Keyur

1
php tarafından dom değişikliği için phpquery kullanmanın daha iyi olduğunu düşünüyorum github.com/punkave/phpQuery
dav

7

DomXPathVeya kullanmadan başka bir yaklaşım daha var Zend_Dom_Query.

Dav'ın orijinal işlevine dayanarak, etiketi ve sınıfı parametrelerle eşleşen ana düğümün tüm alt öğelerini döndüren aşağıdaki işlevi yazdım.

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

$htmlaşağıdaki HTML'ye sahip bir değişkeniniz olduğunu varsayalım :

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

kullanımı getElementsByClassşu kadar basittir:

$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 yazması yavaş ve phpQuery'de bozuk bellek sızıntısı sorunları var. Kullanmaya son verdim:

https://github.com/wasinger/htmlpagedom

Bir sınıf seçmek için:

include 'includes/simple_html_dom.php';

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

Umarım bu başka birine de yardımcı olur

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.