5

私は昨日この質問をしましたが、当時はまさに私が必要としていたものでしたが、いくつかのライブデータを操作しているときに、期待どおりに機能していないことがわかりました。PHP の HTML DOMDocument で HTML を解析する

HTML ページからデータを取得しますが、キャプチャしたテキスト ブロック内のすべての HTML タグも削除します。これは私が望んでいるものではありません。(一部のタグを削除したくないかもしれませんが、すべてではありません。これは後で行うことができます)

4

2 に答える 2

9

これは DOM の一般的な問題です。タグのコンテンツとそのすべての子のコンテンツを取得したい場合は、もう少し作業を行う必要があります。

基本的に、XPath クエリと一致させたノードの子ノードをループして、その内容を取得する必要があります。

DOMElementクラスのマニュアルページでユーザーがメモしたものの1つに提案された解決策があります-このメモを参照してください。


このソリューションを既存のコードに統合すると、次のようなサブタグ付きの HTML 文字列の宣言が得られるはずです。

$html = <<<HTML
<div class="main">
    <div class="text">
        <p>
            Capture this <strong>text</strong> <em>1</em>
        </p>
        <p>
            And some other <strong>text</strong>
        </p>
    </div>
</div>
HTML;


そして、その HTML 文字列からデータを抽出するには、次のようなものを使用できます。

$dom = new DOMDocument();
$dom->loadHTML($html);

$xpath = new DOMXPath($dom);

$tags = $xpath->query('//div[@class="main"]/div[@class="text"]');
foreach ($tags as $tag) {
    $innerHTML = '';

    // see http://fr.php.net/manual/en/class.domelement.php#86803
    $children = $tag->childNodes;
    foreach ($children as $child) {
        $tmp_doc = new DOMDocument();
        $tmp_doc->appendChild($tmp_doc->importNode($child,true));       
        $innerHTML .= $tmp_doc->saveHTML();
    }

    var_dump(trim($innerHTML));
}

変更された唯一のことはforeachloop の内容です。単に を使用する代わりに$tag->nodeValue、子要素を反復処理する必要があります。


次の出力が得られます。

string '<p>
            Capture this <strong>text</strong> <em>1</em>
        </p>


<p>
            And some other <strong>text</strong>
        </p>' (length=150)

これは、一致したタグの完全なコンテンツと、<div>そのすべての子 (タグを含む) です。


注 : マニュアルのユーザー ノートには、興味深いアイデアや解決策が記載されていることがよくあります ;-)

于 2010-04-04T14:16:50.093 に答える
3

Pascal MARTINの答えは素晴らしいですが、単純化できることがわかりました

$dom = new DOMDocument();
$dom->loadHTML($html);

$xpath = new DOMXPath($dom);

$tags = $xpath->query('//div[@class="main"]/div[@class="text"]');
foreach ($tags as $tag) {
    $innerHTML = '';

    $children = $tag->childNodes;
    foreach ($children as $child) {     
        $innerHTML .= $dom->saveHTML($child);
    }

    var_dump(trim($innerHTML));
}

この方法でも同じ結果が得られるように見えますが、ループDomDocument内で新しいオブジェクトを作成する必要はありません。foreach

編集:

したがって、さらに実験した後、実際に上記を次のように減らすことができます。

$dom = new DOMDocument();
$dom->loadHTML($html);

$xpath = new DOMXPath($dom);

$tags = $xpath->query('//div[@class="main"]/div[@class="text"]');
foreach ($tags as $tag) {
    var_dump(trim($dom->saveHTML($tag)));
}
于 2014-05-08T19:24:14.933 に答える