PHPでHTMLのDOMを操作する方法を選ぶ
2023年 3月16日 Posted 野々瀨(フロントエンドエンジニア)
PHPでスクレイピングであったり、動的にHTMLを書き換えたりなど、HTMLを解析しDOMとして操作したいときがあると思います。
そんなPHPでHTMLのDOM操作をしたい場合に使用するモジュールやライブラリを軽くご紹介します。
本記事をご覧いただくにあたって
DOMについて
PHPでDOM操作をする、あるいはしようとしていることが開始地点であるため、DOMについては知っている前提として省略します。
詳細な使い方
DOMを操作する方法がいろいろある中で、あくまで何がよいのか選択をするためで、詳細な使い方はご紹介しません。
使い方を知りたい方は、各公式のドキュメントなどをご参照ください。
DOMを操作するモジュールやライブラリ
PHPでは標準でDOM操作を行えるモジュールがあったり、ライブラリを使用してDOM操作を行ったりすることができます。
モジュールやライブラリについて次の幾つかをご紹介します。
- SimpleXML
- DOMDocument
- Simple HTML DOM Parser
- phpQuery
- PHP Html Parser
- DiDOM
- PHP Selector
- QueryPath
- HTML5DOMDocument
SimpleXML
SimpleXMLは、PHP 5から追加された拡張モジュールで、XMLをオブジェクトとして簡単に操作できます。
モジュールをインストールしていれば標準で扱うことができます。
HTMLは標準で扱うことができず、一度DOMDocumentで解析して、そのオブジェクトを読み込むことで操作できるようになります。
コード例
$xml = simplexml_load_file('./data/sample.xml');
$names = array();
foreach ($xml->items->item as $item) {
$names[] = (string)$item->name;
}
関連リンク
DOMDocument
DOMDocumentは、PHP 5から追加された拡張モジュールで、XMLとHTMLをオブジェクトとして簡単に操作できます。
モジュールをインストールしていれば標準で扱うことができます。
マルチバイトを扱う場合に、数値参照に変換されてしまったりと一部不具合のようなものがありますが、工夫することで回避することはできます。
コード例
$doc = file_get_contents('./data/sample.html');
$dom = new DOMDocument();
libxml_use_internal_errors(true);
$dom->loadHTML($doc, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
libxml_clear_errors();
$title_node = $dom->getElementsByTagName('title')[0];
$title = $title_node->nodeValue;
関連リンク
Simple HTML DOM Parser
Simple HTML DOM Parserは、CSSセレクターでDOM操作を行うことができるライブラリです。
他のDOM解析ライブラリなどにはあまり見ないダンプ機能が付いています。
このライブラリの欠点として、HTMLを取得する際、内部にあるインデントはそのままですが、改行は削除された状態を取得します。
コード例
require_once('simple_html_dom.php');
$dom = file_get_html('./data/sample.html');
$news_titles = array();
foreach ($dom->find('.news li') as $item) {
$news_titles[] = $item->text();
}
関連リンク
phpQuery
phpQueryは、JavaScriptのライブラリであるjQueryのように、CSSセレクターでDOM操作を行うことができるライブラリです。
jQueryのメソッド名がほぼそのまま使われているため、jQueryを扱ったことがあれば似た書き方が可能です。
ただし、最終リリース日が2009年と古いですので、それ以降のjQueryの機能やCSSのセレクターは扱えません。
コード例
require_once('phpQuery.php');
$dom = phpQuery::newDocumentFile('./data/sample.html');
$anchors = $dom->find('a[href^="#"]');
$links = array();
$anchors->each(function($anchor) {
global $links;
$links[] = pq($anchor)->attr('href');
});
関連リンク
phpquery - Google Code Archive
PHP Html Parser
PHP Html Parserは、JavaScriptのライブラリであるjQueryのように、CSSセレクターでDOM操作を行うことができるライブラリです。
他のモジュールやライブラリと違い、要素はTagというクラスで要素自身の情報をもっていて、取得はもちろんタグ名の変更などもTagで行います。
要素を作成する際はTagクラス、HtmlNodeクラス、テキストが必要であればTextNodeクラスと複数のクラスを組み合わせる必要があります。
コード例
require_once('./vendor/autoload.php');
use PHPHtmlParser\Dom;
use PHPHtmlParser\Options;
use PHPHtmlParser\Dom\Tag;
use PHPHtmlParser\Dom\Node\HtmlNode;
use PHPHtmlParser\Dom\Node\TextNode;
$dom = new Dom;
$options = new Options();
$options->setWhitespaceTextNode(false);
$dom->loadFromFile('./data/sample.html', $options);
$dom->find('.news li')->each(function($item) {
$tag = new Tag('span');
$label_node = new HtmlNode($tag);
$text_node = new TextNode('ラベル');
$label_node->addChild($text_node);
$item->addChild($label_node);
});
関連リンク
paquettg/php-html-parser - GitHub
DiDOM
DiDOMは、CSSセレクターでDOM操作を行うことができるライブラリです。
style属性の解析に対応していて、取得はもちろん設定も可能です。
他のライブラリなどに比べて機能が豊富に感じます。
コード例
require_once('./vendor/autoload.php');
use DiDom\Document;
$dom = new Document();
$dom->preserveWhiteSpace(true);
$dom->loadHtmlFile('./data/sample.html');
$news_titles = array();
foreach ($dom->find('.news li') as $item) {
$news_titles[] = $item->text();
}
関連リンク
PHP Selector
PHP Selectorは、CSSセレクターでDOM操作を行うことができるライブラリです。
他のライブラリと比べ、要素の情報を取得する機能だけのシンプルなライブラリです。
コード例
require_once('selector.inc');
$doc = file_get_contents('./data/sample.html');
$dom = new SelectorDom($doc);
$news_titles = array();
foreach ($dom->select('.news li') as $item) {
$news_titles[] = $item['text'];
}
関連リンク
QueryPath
QueryPathは、JavaScriptのライブラリであるjQueryのように、CSSセレクターでDOM操作を行うことができるライブラリです。
jQueryのメソッド名がほぼそのまま使われているため、jQueryを扱ったことがあれば似た書き方が可能です。
style属性の解析に対応していて、取得はもちろん設定も可能です。
コード例
require_once('./vendor/autoload.php');
$qp = qp('./data/sample.html');
$news_titles = array();
$qp->find('.news li')->each(function($item) {
global $news_titles;
$news_titles[] = $item['text'];
});
関連リンク
technosophos/querypath - GitHub
HTML5DOMDocument
HTML5DOMDocumentは、DOMDocumentでHTML5を扱う際の不具合などを解消したライブラリです。
DOMDocumentの機能はそのままに、JavaScriptにあるquerySelector / querySelectorAllメソッド
といった機能も備わっています。
コード例
require_once('./vendor/autoload.php');
$dom = new IvoPetkov\HTML5DOMDocument();
$dom->loadHTML($doc, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$news_titles = array();
foreach ($dom->querySelectorAll('.news li') as $item) {
$news_titles[] = $item['text'];
}
関連リンク
ivopetkov/html5-dom-document-php - GitHub
簡単な比較
項目 | SimpleXML | DOMDocument | Simple HTML DOM Parser | phpQuery | PHP Html Parser | DiDOM | PHP Selector | QueryPath | HTML5DOMDocument |
---|---|---|---|---|---|---|---|---|---|
最終リリース日 | - | - | 2019/10/20 | 2009/5/2 | 2020/11/2 | 2022/5/8 | 2014/10/20 | 2016/8/2 | 2022/4/26 |
バージョン | - | - | 1.9.1 | 0.9.5 | 3.1.1 | 2.0.0 | 1.1.5 | 3.0.5 | 2.3.1 |
PHPバージョン | 5~8 | 5~8 | 5.6.0~ | 5系~(注1) | 7.2.0~7.4.0、 8.0.x~(注2) | 7.2.0~、 8.0.x~(注2) | 5.2.8~、 8.0.x~(注2) | 5.2.0~、 8.0.x~(注2) | 7.0.x~8.1.0 |
マークアップ言語 | XML | XML、 HTML、 XHTML、 HTML5 | XML、 HTML、 XHTML、 HTML5 | XML、 HTML、 XHTML、 HTML5 | XML、 HTML、 XHTML、 HTML5 | XML、 HTML、 XHTML、 HTML5 | XML、 HTML、 XHTML、 HTML5 | XML、 HTML、 XHTML、 HTML5 | XML、 HTML、 XHTML、 HTML5 |
文字コード | UTF-8、 Shift_JIS、 他 | UTF-8、 Shift_JIS、 他 | UTF-8、 Shift_JIS、 他 | UTF-8、 Shift_JIS、 他 | UTF-8、 他 | UTF-8、 Shift_JIS、 他 | UTF-8、 Shift_JIS、 他 | UTF-8、 Shift_JIS、 他 | UTF-8、 Shift_JIS、 他 |
操作可能なノード | 要素、 属性、 CDATA、 他 | 要素、 属性、 テキスト、 CDATA、 他 | 要素、 属性、 テキスト、 他 | 要素、 属性、 テキスト、 他 | 要素、 属性、 テキスト、 他 | 要素、 属性、 テキスト、 他 | 要素、 属性、 テキスト | 要素、 属性、 テキスト、 他 | 要素、 属性、 テキスト、 CDATA、 他 |
ノードの取得(検索)方法 | アロー演算子でたどる、 xPath | ID名、 タグ名、 xPath | CSSセレクター、 ID名、 タグ名 | CSSセレクター | CSSセレクター、 ID名、 タグ名 | CSSセレクター、 xPath | CSSセレクター | CSSセレクター、 xPath | ID名、 タグ名、 xPath、 CSSセレクター |
マークアップ全体の出力 | あり | あり | あり | あり | あり | あり | なし | あり | あり |
ファイルへの直接保存 | あり | あり | あり | なし | なし | なし | なし | なし | あり |
- (注1) ~系と表記されているところは詳細なバージョンが不明です。
- (注2) PHP 8系でも動作しますが、公式ではなく筆者が確認した結果です。
選定
ネイティブで扱うならDOMDocument、DOMDocumentにおいて自身で一部のエラー解消が不安な場合はHTML5DOMDocument、ライブラリなら操作が簡単で多機能な更新もされているDiDOM(PHP 5系で動かすならQueryPath)といったところでしょうか。
筆者は昔、ライブラリではやりたいことが実現できなかったため、DOMDocumentで開発していました。
最近(というほどでもないですが)はライブラリが豊富に展開され、実現できることがかなり増え、操作も簡単になっているため、より実装しやすくなっています。