PHP DOM を使用しており、特定のクラス名を持つDOMノード内の要素を取得しようとしています。そのサブ要素を取得する最良の方法は何ですか?
更新:PHPにMechanize
を使用することになりました。
更新:*[@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')]");
要素の種類が1つだけの場合は、*
を特定のタグ名に置き換えることができます。
非常に複雑なセレクタでこれをたくさん行う必要がある場合は、CSSセレクタ構文をサポートする Zend_Dom_Query
をお勧めします(jQueryに似ています):
$Finder = new Zend_Dom_Query($html);
$classname = 'my-class';
$nodes = $Finder->query("*[class~=\"$classname\"]");
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;
受け入れられた方法の方が良いと思いますが、これもうまくいくと思います
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;
}
DOMDocumentはタイプが遅く、phpQueryにはメモリリークの問題があります。私は最終的に使用しました:
https://github.com/wasinger/htmlpagedom
クラスを選択するには:
include 'includes/simple_html_dom.php';
$doc = str_get_html($html);
$href = $doc->find('.lastPage')[0]->href;
これが他の人にも役立つことを願っています
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".