c/fe

http://d.hatena.ne.jp/uzulla から移行しました。

PHP の Dom操作で、特定のタグの中のHTMLを抜き出す

ある案件で、リモートのHTMLをインクルードして出力するという要件があった。
まあなにも考えないで書くと

$file = file_get_contents($url);

こんな感じでリモートのHTMLは取得できる。

だがしかし、これだとメタタグなども取得してしまうし、HTMLやHEAD、BODYタグもでてしまう、いささか不味い。



ということで、BODYの中のHTMLだけを抜き出す必要がある。
それはこんな感じでできる

$file = file_get_contents($url);
preg_match( "/<body>(.*?)<\/body>/i", $file, $tmp) 
file = $tmp[0];

…こんなダメなコードは書いたらダメですね。
うごくかわかったもんじゃないです。

正規表現で切り貼りするのが許されるのは(略



ってことでDOMでやります。

    $opts = array(
            'http'=>array(
                    'method'=>"GET",
                    'header'=>"Accept-language: ja\r\n" 
            )
    );
    $context = stream_context_create($opts);

    $file = file_get_contents($url, false, $context);
    $file = mb_convert_encoding($file, 'UTF-8', mb_detect_encoding($file));

    libxml_use_internal_errors(TRUE);
    $document = new DOMDocument();
    $document->recover = 1;
    $document->loadHTML($file);

    $body = $document->getElementsByTagName('body');
    $childelms = $body->item(0)->childNodes;
    for($i=0; $childelms->length > $i; $i++) {
      $rtn .= $document->saveXML($childelms->item($i));
    }

    $rtn = mb_convert_encoding($rtn, $charset,'UTF-8');
    libxml_use_internal_errors(FALSE);
    return $rtn;

ばっちりですね。
コードは長いですけど、正規表現のマッチミスに不安になったり、文字コードのことを心配する必要がほぼ有りません。


しっかし、

    for($i=0; $childelms->length > $i; $i++) {
      $rtn .= $document->saveXML($childelms->item($i));
    }

ってまったく直感的じゃないですよね…。

    for($childelms as $elm) {
      $rtn .= $elm->saveXML();
    }

ってやりたいですよね…。