PowerCMS X ブログ

2024-12-10

PHPの Domで querySelectorや jQueryの find相当の処理を行いたい

PowerCMS Xのデータ移行処理や やさしい日本語関連の処理等で PHPの DomDocument を使うことが多いのですが、querySelector / querySelectorAll が使えず、 jQueryの find相当の処理などもできないので、自前で書くしかありませんでした。PHP8.4で querySelector / querySelectorAll がようやくサポートされ、HTML5 ドキュメントもパースできるようになりました。

新しい DOM API では、標準に沿った HTML5 ドキュメントのパース機能が追加され、古くからある標準に準拠しない複数の DOM 機能の振る舞いに関する不具合が修正され、ドキュメントの操作がより便利になるいくつかの関数が追加されました。

ありがたいですね。でも、今すぐ使いたい、PHP8.2でも使いたい、PowerCMS Xとしてもサポートしたい、ということで DomDocument と DOMElementを拡張したクラスを作成しました。継承しているので、DomDocument / DOMElement のメソッドなどは基本的にそのまま使えます次回のバージョンアップ時に lib/Prototype/ 配下に追加されます)。

ライブラリPhpGt/CssXPathが必要です。

PhpGt/CssXPath [Translator CSS selectors to XPath queries]

PTDomDocument クラス

DomDocumentを拡張したクラス

メソッド

loadHTML( string $html ) : bool

文字列から HTML を読み込む (先頭のBOMを削除してHTMLエンティティに変換して読み込む)

loadHTMLFile( string $path ) : bool

ファイルから HTML を読み込む

saveHTML( ?DOMNode $node = null ) string | bool

内部のドキュメントを HTML 形式の文字列として出力する
$node が省略された時 HTMLエンティティをオリジナルのテキストに変換しなおす

getElementsByClassName( string $className ) : DOMNodeList

指定されたクラス名をすべて持つすべての子要素の DOMNodeList を返す

querySelector( string $selectors ) : PTDOMElement

指定されたセレクターまたはセレクター群に一致する、文書内の最初の PTDOMElement を返す

querySelectorAll( string $selectors ) : DOMNodeList

指定されたセレクターまたはセレクター群に一致する、文書内のすべての要素の DOMNodeList を返す

query( string $xpath ) : DOMNodeList

指定された $xpath に一致する、文書内のすべての要素の DOMNodeList を返す

selector2xpath( string $selectors ) : string

指定されたセレクターまたはセレクター群を Xpath に変換した文字列を返す

PTDOMElement クラス

DOMElementを拡張したクラス

プロパティ

innerHTML : string

要素内の HTML 文字列

outerHTML : string

要素とその子孫を含む部分の HTML 文字列 (読み取りのみ)

childrenElements : PTDOMNodeList

要素配下のすべての PTDOMElement の PTDOMNodeList (読み取りのみ)

メソッド

find( string $selectors ) : PTDOMNodeList

指定されたセレクターまたはセレクター群に一致する、要素内のすべての要素の PTDOMNodeList を返す

next( string $selectors ) : PTDOMElement

要素の「直後」にあたる兄弟要素を返す

prev( string $selectors ) : PTDOMElement

要素の「直前」にあたる兄弟要素を返す

siblings( string $selectors, bool $self = false ) : PTDOMNodeList

要素の兄弟要素の PTDOMNodeList を返す ( $self = 自分自身を含む | 含まない )

nextAll( string $selectors ) : PTDOMNodeList

要素の兄弟要素のうち要素の「後」に出現する PTDOMNodeList を返す

prevAll( string $selectors ) : PTDOMNodeList

要素の兄弟要素のうち要素の「前」に出現する PTDOMNodeList を返す

innerHTML( string $html = null ) string | bool

要素内の HTML を返す
$html を指定した場合は要素内の HTML をセットする

outerHTML() : string

要素とその子孫を含む部分の HTML 文字列を返す

getElementsByClassName( string $selectors ) : PTDOMNodeList

指定されたクラス名をすべて持つすべての子孫要素の PTDOMNodeList を返す

getChildrenElements() : PTDOMNodeList

要素配下のすべての子孫要素 (PTDOMElement) の PTDOMNodeList を返す

PTDOMNodeList クラス

PTDOMElement オブジェクトのリスト

プロパティ

length : int

リスト内のノードの数

メソッド

count() : int

リストにあるノードの数を取得する

item( int $index ) : PTDOMElement

インデックスで指定したノードを取得する


サンプル

PowerCMS Xサイトの 事例紹介 https://powercmsx.jp/cases/index.html から HTMLを取得して JSON形式で返却するサンプルコードです。

<?php
require_once( '/path/to/class.PTDomDocument.php' );
require_once( '/path/to/Translator.php' );
$dom = new PTDomDocument();
$url = 'https://powercmsx.jp/cases/index.html';
$dom->loadHTMLFile( $url );
$json = [];
$basicInfo = $dom->querySelectorAll( '.basicInfo' );
// $basicInfo = $dom->getElementsByClassName( 'basicInfo' );
foreach ( $basicInfo as $info ) {
    $anchor = $info->find( 'h2 a' )->item( 0 );
    $company = $anchor->innerHTML;
    $link = $anchor->getAttribute( 'href' );
    $text = $info->find( 'h3 + p' )->item( 0 )->innerHTML;
    $subtitle = $info->find( 'h3 a' )->item( 0 )->innerHTML;
    $img = $info->find( 'img' )->item( 0 );
    $thumbnail = ['src' => $img->getAttribute( 'src' ), 'alt' => $img->getAttribute( 'alt' )];
    $json[] = ['company' => $company,
               'subtitle' => $subtitle,
               'url' => $link,
               'text' => $text,
               'thumbnail' => $thumbnail,
               ];
}
header( 'Content-type: application/json; charset=UTF-8' );
echo json_encode( $json, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT );

カテゴリー:技術情報

投稿者:Junnama Noda

ブログ内検索

アーカイブ