クラス名によるDOM要素の取得


回答:


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属性を正規化することだけなので、1つのクラスでもスペースで囲まれ、完全なクラスリストはスペースで囲まれます。次に、検索するクラスにスペースを追加します。このようにして、のインスタンスのみを効果的に探して見つけますmy-class


xpathセレクターを使用しますか?

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

要素が1種類しかない場合は*、特定のタグ名に置き換えることができます。

非常に複雑なセレクターでこれをたくさん行う必要がある場合Zend_Dom_Query、CSSセレクター構文をサポートするものをお勧めします(la jQuery)。

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

クラスmy-class2も見つけますが、かなり甘いです。すべての要素の最初のものだけを選択する方法はありますか?
hakre

xpath2がなくてもできるとは思いません...しかし、Zend_Dom_Queryの例はまさにそれを実行します。プロジェクトでそのcompkenetを使用したくない場合は、cssセレクターをxpathに変換する方法を確認する必要があります。DomXPathはxpath 2.0をサポートしているのかもしれません-よくわかりません。
プロデジタルソン、2011年

1
classたとえば、複数のクラスを持つことができるからです<a class="my-link link-button nav-item">
プロデジタルソン2011年

2
@prodigitalson:スペースを反映していないため、これは正しくありません。試してください//*[contains(concat(' ', normalize-space(@class), ' '), ' classname ')](非常に参考:CSSセレクターとXPath式)。
ハクレ

1
@babonk:はい、あなたcontainsは組み合わせて使用する必要がありますconcat...私たちはあなたが探しているクラスの両側のスペースを埋めるか、片側だけを埋める詳細について話し合っています。どちらでもうまくいくはずです。
プロデジタルソン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'
カミル

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

それは素晴らしいことです。クラスで要素を取得しました。次に、クラスを含む要素に子を追加するなど、要素のコンテンツを編集します。子を追加してHTML全体を再作成する方法は?助けてください。これは私がやったことです。$classResult = getElementByClass($dom, 'div', 'm-signature-pad'); $classResult->nodeValue = ''; $enode = $dom->createElement('img'); $enode->setAttribute('src', $signatureImage); $classResult->appendChild($enode);
Keyur 2016年

1
phpによるdomの変更については、phpquery github.com/punkave/phpQuery
dav

7

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

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;

これが他の誰かにも役立つことを願っています

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.