1. DOMDocumentとDOMXPathを使う
PHPでXPathを使うには、DOMDocumentを利用してXML/HTMLをロードし、DOMXPathオブジェクトを作成してquery()を実行します。
基本的な使い方
php<?php
$xml = <<<XML
<books>
<book id="1">
<title>PHP入門</title>
<author>山田 太郎</author>
</book>
<book id="2">
<title>JavaScriptの世界</title>
<author>佐藤 次郎</author>
</book>
</books>
XML;
// DOMDocumentを作成し、XMLを読み込む
$dom = new DOMDocument();
$dom->loadXML($xml);
// XPathオブジェクトを作成
$xpath = new DOMXPath($dom);
// XPathクエリを実行(すべての<book>要素を取得)
$books = $xpath->query("//book");
// 結果を表示
foreach ($books as $book) {
$title = $xpath->query("title", $book)->item(0)->nodeValue;
$author = $xpath->query("author", $book)->item(0)->nodeValue;
echo "タイトル: $title, 著者: $author\n";
}
?>
XPathクエリの例
| XPath クエリ | 説明 |
|---|---|
//book | <book>要素をすべて取得 |
//book[@id='1'] | id="1" の <book> 要素を取得 |
//book/title | すべての <book> の <title> を取得 |
//book[author='山田 太郎'] | 著者が”山田 太郎”の <book> 要素を取得 |
HTMLの解析
XMLだけでなく、HTMLも解析できます。
php<?php
$html = <<<HTML
<html>
<body>
<div class="content">Hello World</div>
<div class="content">PHPとXPath</div>
</body>
</html>
HTML;
$dom = new DOMDocument();
libxml_use_internal_errors(true); // HTMLの警告を無視
$dom->loadHTML($html);
$xpath = new DOMXPath($dom);
$nodes = $xpath->query("//div[@class='content']");
foreach ($nodes as $node) {
echo $node->nodeValue . "\n";
}
?>
結果
nginxHello World
PHPとXPath
まとめ
DOMDocumentでXML/HTMLを読み込むDOMXPathでquery()を使いノードを取得- XPathクエリで要素を選択する
PHPのXPath 2.0以降では matches() 関数を使えますが、
PHPのDOMXPathはXPath 1.0のみ対応しているため、matches()関数はサポートされていません。
そのため、XPath 1.0の代替手段を使う必要があります。
しかし、もし matches() のような正規表現マッチングを行いたい場合は、
PHPのpreg_match()を組み合わせることで同様の処理が可能です。
matches() の代替方法
1. matches() の代わりに contains() を使う
XPath 1.0には matches() はありませんが、部分一致なら contains() で対応できます。
例:title に “PHP” を含む <book> を取得
php<?php
$xml = <<<XML
<books>
<book>
<title>PHP入門</title>
</book>
<book>
<title>JavaScriptの世界</title>
</book>
<book>
<title>PHPとMySQL</title>
</book>
</books>
XML;
$dom = new DOMDocument();
$dom->loadXML($xml);
$xpath = new DOMXPath($dom);
// "PHP" を含むタイトルを取得(matches()の代替)
$nodes = $xpath->query("//book[contains(title, 'PHP')]");
foreach ($nodes as $node) {
echo $node->textContent . "\n";
}
?>
結果
PHP入門
PHPとMySQL
2. preg_match() で正規表現を使う
XPath 1.0には matches() がないため、PHPの preg_match() を使って結果を
フィルタリングできます。
例:title が “PHP” または “JavaScript” を含む <book> を取得
php<?php
$xml = <<<XML
<books>
<book>
<title>PHP入門</title>
</book>
<book>
<title>JavaScriptの世界</title>
</book>
<book>
<title>Pythonプログラミング</title>
</book>
</books>
XML;
$dom = new DOMDocument();
$dom->loadXML($xml);
$xpath = new DOMXPath($dom);
// すべての <book> を取得
$nodes = $xpath->query("//book");
foreach ($nodes as $node) {
$title = $xpath->query("title", $node)->item(0)->nodeValue;
// `matches()` の代わりに `preg_match()` を使用
if (preg_match('/PHP|JavaScript/', $title)) {
echo "マッチ: $title\n";
}
}
?>
結果
makefileマッチ: PHP入門
マッチ: JavaScriptの世界
3. translate() を使って大文字・小文字を無視
XPath 1.0 では大文字・小文字の区別をなくすために translate() を使うことができます。
例:”php” という単語が含まれている <book> を取得(大文字・小文字を無視)
php<?php
$xml = <<<XML
<books>
<book>
<title>PHP入門</title>
</book>
<book>
<title>javascriptとPHP</title>
</book>
<book>
<title>Pythonプログラミング</title>
</book>
</books>
XML;
$dom = new DOMDocument();
$dom->loadXML($xml);
$xpath = new DOMXPath($dom);
// 小文字に変換してから比較
$query = "//book[contains(translate(title, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), 'php')]";
$nodes = $xpath->query($query);
foreach ($nodes as $node) {
echo "マッチ: " . $xpath->query("title", $node)->item(0)->nodeValue . "\n";
}
?>
結果
makefileマッチ: PHP入門
マッチ: javascriptとPHP
まとめ
| 目的 | XPath 1.0 の代替方法 |
|---|---|
matches() の代用 | preg_match() を使う |
| 部分一致 | contains() を使う |
| 大文字・小文字を無視 | translate() を使う |
| 正規表現 | preg_match() を使う |
PHPの DOMXPath は matches() を直接サポートしていませんが、contains() や preg_match() を活用すれば同様の処理が可能です!
XPath 1.0 では、@class 属性が複数の値を持つ場合に、
特定のクラスが含まれているかを判定する方法
として contains() を使用します。
複数のクラスを指定する方法
1. AND条件(すべてのクラスを含む)
特定の class 値を すべて含む要素 を取得するには、contains() を
複数回使う ことで対応できます。
php<?php
$html = <<<HTML
<html>
<body>
<div class="box red">Red Box</div>
<div class="box blue">Blue Box</div>
<div class="box red blue">Red and Blue Box</div>
</body>
</html>
HTML;
$dom = new DOMDocument();
libxml_use_internal_errors(true); // HTMLの警告を無視
$dom->loadHTML($html);
$xpath = new DOMXPath($dom);
// `class` に "red" と "blue" の両方を含む要素を取得
$query = "//div[contains(@class, 'red') and contains(@class, 'blue')]";
$nodes = $xpath->query($query);
foreach ($nodes as $node) {
echo $node->nodeValue . "\n";
}
?>
結果
mathematicaRed and Blue Box
2. OR条件(いずれかのクラスを含む)
@class に "red" または "blue" の どちらかが含まれる要素 を取得する場合、or を使います。
php$query = "//div[contains(@class, 'red') or contains(@class, 'blue')]";
PHPコード
php<?php
$nodes = $xpath->query("//div[contains(@class, 'red') or contains(@class, 'blue')]");
foreach ($nodes as $node) {
echo $node->nodeValue . "\n";
}
?>
結果
mathematicaRed Box
Blue Box
Red and Blue Box
3. 厳密にクラスを指定(完全一致)
@class="red blue" のように 順番も含めて完全一致 を求める場合は、normalize-space() を使います。
php$query = "//div[normalize-space(@class) = 'red blue']";
PHPコード
php<?php
$nodes = $xpath->query("//div[normalize-space(@class) = 'red blue']");
foreach ($nodes as $node) {
echo $node->nodeValue . "\n";
}
?>
結果
mathematicaRed and Blue Box
注意:
normalize-space()は@classの前後の空白を削除しますが、
順番が異なる (blue red) 場合には一致しません。
4. クラスを正規表現で判定
PHPの preg_match() を使って、より柔軟にクラス名を判定することもできます。
php<?php
foreach ($xpath->query("//div") as $node) {
$class = $node->getAttribute("class");
// "red" と "blue" の両方を含むクラスを正規表現でチェック
if (preg_match('/\bred\b/', $class) && preg_match('/\bblue\b/', $class)) {
echo $node->nodeValue . "\n";
}
}
?>
結果
mathematicaRed and Blue Box
まとめ
| 条件 | XPath クエリ |
|---|---|
| AND条件(両方のクラスを含む) | contains(@class, 'red') and contains(@class, 'blue') |
| OR条件(どちらかのクラスを含む) | contains(@class, 'red') or contains(@class, 'blue') |
| 完全一致(順番も含める) | normalize-space(@class) = 'red blue' |
| 正規表現で厳密チェック | preg_match('/\bred\b/', $class) && preg_match('/\bblue\b/', $class) |
XPath 1.0 では matches() が使えないため、contains() を組み合わせるか、
PHPの preg_match() を活用すると柔軟に対応できます!

