1. 関数概要
tidy_is_xml は、PHP の Tidy 拡張が解析したドキュメントが XML であるかどうかを判定する関数です。XML 宣言や DOCTYPE をもとに Tidy ライブラリが内部的に判定した結果を bool で返します。HTML・XHTML・XML が混在するシステムでのドキュメント種別の振り分け、バリデーションパイプラインの条件分岐、出力形式の自動選択などに活用できます。
| 項目 | 内容 |
|---|---|
| 関数名 | tidy_is_xml |
| 所属拡張 | Tidy |
| 戻り値の型 | bool |
| 手続き型 / OOP | 手続き型(OOP 版: $tidy->isXml()) |
| PHP バージョン | PHP 5 以降 |
| 公式ドキュメント | https://www.php.net/manual/ja/tidy.isxml.php |
2. 構文
// 手続き型
tidy_is_xml(tidy $tidy): bool
// オブジェクト指向型
$tidy->isXml(): bool
パラメータ
| パラメータ | 型 | 説明 |
|---|---|---|
$tidy | tidy | tidy_parse_string() 等で生成した tidy オブジェクト |
戻り値
| 戻り値 | 意味 |
|---|---|
true | ドキュメントが XML であると判定された |
false | XML ではない(HTML・XHTML またはその他) |
3. tidy_is_xml / tidy_is_xhtml / HTML の判定比較
| 入力ドキュメントの種別 | tidy_is_xml() | tidy_is_xhtml() |
|---|---|---|
| HTML 4.01 | false | false |
| HTML5 | false | false |
| XHTML 1.0 Strict | false | true |
| XHTML 1.0 Transitional | false | true |
| 純粋な XML(非 HTML) | true | false |
| DOCTYPE なし | false | false |
ポイント: XHTML は XML のサブセットですが、Tidy の判定では
tidy_is_xml()とtidy_is_xhtml()は独立した判定です。XHTML ドキュメントに対してtidy_is_xml()がtrueを返すとは限りません。
4. 動作概念図
┌──────────────────────────────────────────────────────────────┐
│ 入力ドキュメントのパターン │
│ │
│ パターンA: 純粋な XML │
│ <?xml version="1.0"?> │
│ <root><item>値</item></root> │
│ ※ HTML/XHTML DOCTYPE なし │
│ │
│ パターンB: XHTML(XML サブセット) │
│ <?xml version="1.0"?> │
│ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 ..."> │
│ <html xmlns="http://www.w3.org/1999/xhtml">...</html> │
│ │
│ パターンC: HTML5 │
│ <!DOCTYPE html><html>...</html> │
└───────────────────────┬──────────────────────────────────────┘
│ tidy_parse_string()
▼
┌──────────────────────────────────────────────────────────────┐
│ Tidy 解析エンジン │
│ XML 宣言・DOCTYPE・名前空間をもとに判定 │
└───────────┬───────────────────────┬──────────────────────────┘
│ tidy_is_xml() │ tidy_is_xhtml()
▼ ▼
A: true B: false C: false A: false B: true C: false
5. 基本的な使い方
<?php
// 純粋な XML ドキュメント
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<catalog>
<book id="1">
<title>PHPプログラミング</title>
<price>3200</price>
</book>
</catalog>';
$tidy = tidy_parse_string($xml, [], 'UTF8');
if (tidy_is_xml($tidy)) {
echo "✅ このドキュメントは XML です。" . PHP_EOL;
} else {
echo "ℹ️ このドキュメントは XML ではありません。" . PHP_EOL;
}
出力例:
✅ このドキュメントは XML です。
6. 実践的なコード例
例1: ドキュメント種別を3方向で判定するクラス
<?php
class DocumentKindDetector
{
private tidy $tidy;
public function __construct(string $source)
{
$this->tidy = tidy_parse_string($source, [], 'UTF8');
}
public function isXml(): bool { return tidy_is_xml($this->tidy); }
public function isXhtml(): bool { return tidy_is_xhtml($this->tidy); }
public function isHtml(): bool { return !$this->isXml() && !$this->isXhtml(); }
public function getKind(): string
{
return match(true) {
$this->isXml() => 'XML',
$this->isXhtml() => 'XHTML',
default => 'HTML / その他',
};
}
public function report(): void
{
echo "種別 : " . $this->getKind() . PHP_EOL;
echo "tidy_is_xml() : " . var_export($this->isXml(), true) . PHP_EOL;
echo "tidy_is_xhtml(): " . var_export($this->isXhtml(), true) . PHP_EOL;
echo "HTML ver : " . tidy_get_html_ver($this->tidy) . PHP_EOL;
echo "ステータス : " . tidy_get_status($this->tidy) . PHP_EOL;
}
}
$sources = [
'純粋な XML' => '<?xml version="1.0"?><root><item>値</item></root>',
'XHTML 1.0' => '<?xml version="1.0"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title>X</title></head><body><p>XHTML</p></body></html>',
'HTML5' => '<!DOCTYPE html><html><head><title>H5</title></head><body><p>HTML5</p></body></html>',
];
foreach ($sources as $label => $source) {
echo "=== {$label} ===" . PHP_EOL;
(new DocumentKindDetector($source))->report();
echo PHP_EOL;
}
出力例:
=== 純粋な XML ===
種別 : XML
tidy_is_xml() : true
tidy_is_xhtml(): false
HTML ver : 0
ステータス : 0
=== XHTML 1.0 ===
種別 : XHTML
tidy_is_xml() : false
tidy_is_xhtml(): true
HTML ver : 0
ステータス : 0
=== HTML5 ===
種別 : HTML / その他
tidy_is_xml() : false
tidy_is_xhtml(): false
HTML ver : 0
ステータス : 0
例2: OOP スタイルで isXml() を使う
<?php
class TidyOopXmlChecker
{
private tidy $tidy;
public function __construct(string $source, array $config = [])
{
$this->tidy = new tidy();
$this->tidy->parseString($source, $config, 'UTF8');
$this->tidy->cleanRepair();
}
public function check(): void
{
$isXml = $this->tidy->isXml();
$isXhtml = $this->tidy->isXhtml();
echo "isXml() : " . var_export($isXml, true) . PHP_EOL;
echo "isXhtml(): " . var_export($isXhtml, true) . PHP_EOL;
echo "判定結果 : " . match(true) {
$isXml => '✅ XML',
$isXhtml => '✅ XHTML',
default => 'ℹ️ HTML / その他',
} . PHP_EOL;
}
}
$xmlSource = '<?xml version="1.0" encoding="UTF-8"?><data><value>42</value></data>';
echo "--- XML ---" . PHP_EOL;
(new TidyOopXmlChecker($xmlSource))->check();
echo PHP_EOL . "--- HTML5 ---" . PHP_EOL;
(new TidyOopXmlChecker('<!DOCTYPE html><html><body><p>HTML5</p></body></html>'))->check();
出力例:
--- XML ---
isXml() : true
isXhtml(): false
判定結果 : ✅ XML
--- HTML5 ---
isXml() : false
isXhtml(): false
判定結果 : ℹ️ HTML / その他
例3: 複数ファイルを一括判定して種別ごとに仕分けるクラス
<?php
class DocumentSorter
{
/** @var array<string, list<string>> */
private array $buckets = ['XML' => [], 'XHTML' => [], 'HTML' => []];
public function addAll(array $documents): self
{
foreach ($documents as $name => $source) {
$tidy = tidy_parse_string($source, [], 'UTF8');
$kind = match(true) {
tidy_is_xml($tidy) => 'XML',
tidy_is_xhtml($tidy) => 'XHTML',
default => 'HTML',
};
$this->buckets[$kind][] = $name;
}
return $this;
}
public function printResult(): void
{
echo "=== ドキュメント種別仕分け結果 ===" . PHP_EOL;
foreach ($this->buckets as $kind => $names) {
echo "[{$kind}] " . count($names) . " 件" . PHP_EOL;
foreach ($names as $name) {
echo " - {$name}" . PHP_EOL;
}
}
}
}
$sorter = new DocumentSorter();
$sorter->addAll([
'config.xml' => '<?xml version="1.0"?><config><debug>true</debug></config>',
'feed.xml' => '<?xml version="1.0"?><rss version="2.0"><channel><title>Blog</title></channel></rss>',
'page.xhtml' => '<?xml version="1.0"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title>X</title></head><body><p>X</p></body></html>',
'index.html' => '<!DOCTYPE html><html><body><p>HTML5</p></body></html>',
'legacy.html' => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"><html><body><p>HTML4</p></body></html>',
])->printResult();
出力例:
=== ドキュメント種別仕分け結果 ===
[XML] 2 件
- config.xml
- feed.xml
[XHTML] 1 件
- page.xhtml
[HTML] 2 件
- index.html
- legacy.html
例4: XML の場合に専用パーサーへ誘導するルーティングクラス
<?php
class DocumentRouter
{
public function route(string $name, string $source): void
{
$tidy = tidy_parse_string($source, [], 'UTF8');
match(true) {
tidy_is_xml($tidy) => $this->handleXml($name, $source),
tidy_is_xhtml($tidy) => $this->handleXhtml($name, $source),
default => $this->handleHtml($name, $source),
};
}
private function handleXml(string $name, string $source): void
{
echo "[XML ルート] {$name} → SimpleXML で処理します。" . PHP_EOL;
$xml = simplexml_load_string($source);
echo " ルート要素: <" . $xml->getName() . ">" . PHP_EOL;
}
private function handleXhtml(string $name, string $source): void
{
echo "[XHTML ルート] {$name} → XHTML バリデーターへ送ります。" . PHP_EOL;
}
private function handleHtml(string $name, string $source): void
{
$tidy = tidy_parse_string($source, ['indent' => true], 'UTF8');
tidy_clean_repair($tidy);
echo "[HTML ルート] {$name} → Tidy で修復・整形します。" . PHP_EOL;
echo " 整形後バイト数: " . strlen(tidy_get_output($tidy)) . PHP_EOL;
}
}
$router = new DocumentRouter();
$router->route('data.xml', '<?xml version="1.0"?><items><item>A</item><item>B</item></items>');
$router->route('index.html','<!DOCTYPE html><html><body><p>HTML</p></body></html>');
出力例:
[XML ルート] data.xml → SimpleXML で処理します。
ルート要素: <items>
[HTML ルート] index.html → Tidy で修復・整形します。
整形後バイト数: 183
例5: 判定結果をログに記録するクラス
<?php
class DocumentTypeLogger
{
public function __construct(private readonly string $logFile) {}
public function log(string $label, string $source): void
{
$tidy = tidy_parse_string($source, [], 'UTF8');
$isXml = tidy_is_xml($tidy);
$isXhtml = tidy_is_xhtml($tidy);
$kind = match(true) {
$isXml => 'XML',
$isXhtml => 'XHTML',
default => 'HTML',
};
$line = sprintf(
"[%s] %-20s | kind=%-5s | isXml=%-5s | isXhtml=%-5s | status=%d\n",
date('Y-m-d H:i:s'),
$label,
$kind,
$isXml ? 'true' : 'false',
$isXhtml ? 'true' : 'false',
tidy_get_status($tidy)
);
file_put_contents($this->logFile, $line, FILE_APPEND);
echo $line;
}
}
$logger = new DocumentTypeLogger('/tmp/doctype_audit.log');
$logger->log('feed.xml', '<?xml version="1.0"?><rss><channel><title>Blog</title></channel></rss>');
$logger->log('page.xhtml', '<?xml version="1.0"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title>X</title></head><body></body></html>');
$logger->log('index.html', '<!DOCTYPE html><html><body><p>HTML5</p></body></html>');
出力例:
[2026-07-19 12:00:00] feed.xml | kind=XML | isXml=true | isXhtml=false | status=0
[2026-07-19 12:00:00] page.xhtml | kind=XHTML | isXml=false | isXhtml=true | status=0
[2026-07-19 12:00:00] index.html | kind=HTML | isXml=false | isXhtml=false | status=0
例6: output-xml オプションとの関係を検証するクラス
<?php
/**
* tidy_is_xml() は「入力」の種別判定。
* output-xml オプションは「出力」形式の制御。
* 両者は独立しており、混同に注意。
*/
class XmlInputOutputInspector
{
public function inspect(string $source, array $config): void
{
// 入力判定(config の影響を受けない)
$tidyIn = tidy_parse_string($source, [], 'UTF8');
$isXml = tidy_is_xml($tidyIn);
// 出力生成(config の output-xml が効く)
$tidyOut = tidy_parse_string($source, $config, 'UTF8');
tidy_clean_repair($tidyOut);
$outputXml = (bool) tidy_getopt($tidyOut, 'output-xml');
$output = tidy_get_output($tidyOut);
echo "--- 入力判定 ---" . PHP_EOL;
echo "tidy_is_xml() : " . var_export($isXml, true) . PHP_EOL;
echo PHP_EOL;
echo "--- 出力設定 ---" . PHP_EOL;
echo "output-xml : " . var_export($outputXml, true) . PHP_EOL;
echo PHP_EOL;
echo "--- 出力(先頭120文字)---" . PHP_EOL;
echo substr($output, 0, 120) . "..." . PHP_EOL;
}
}
$inspector = new XmlInputOutputInspector();
// HTML5 入力を XML 形式で出力
echo "=== HTML5 入力 → output-xml=true ===" . PHP_EOL;
$inspector->inspect(
'<!DOCTYPE html><html><body><p>テスト</p></body></html>',
['output-xml' => true, 'indent' => true]
);
出力例:
=== HTML5 入力 → output-xml=true ===
--- 入力判定 ---
tidy_is_xml() : false ← 入力は HTML5 なので false
--- 出力設定 ---
output-xml : true ← オプションで XML 出力を指定
--- 出力(先頭120文字)---
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-s...
例7: 種別判定を含む統合プロファイルクラス
<?php
readonly class DocProfile
{
public function __construct(
public bool $isXml,
public bool $isXhtml,
public string $kind,
public int $htmlVersion,
public int $status,
public string $release,
public string $errorBuffer,
) {}
}
class DocumentProfiler
{
public function profile(string $source): DocProfile
{
$tidy = tidy_parse_string($source, [], 'UTF8');
$isXml = tidy_is_xml($tidy);
$isXhtml = tidy_is_xhtml($tidy);
return new DocProfile(
isXml: $isXml,
isXhtml: $isXhtml,
kind: match(true) { $isXml => 'XML', $isXhtml => 'XHTML', default => 'HTML' },
htmlVersion: tidy_get_html_ver($tidy),
status: tidy_get_status($tidy),
release: tidy_get_release(),
errorBuffer: tidy_get_error_buffer($tidy) ?: '',
);
}
public function print(DocProfile $p): void
{
echo "=== ドキュメントプロファイル ===" . PHP_EOL;
echo "種別 : {$p->kind}" . PHP_EOL;
echo "isXml() : " . var_export($p->isXml, true) . PHP_EOL;
echo "isXhtml() : " . var_export($p->isXhtml, true) . PHP_EOL;
echo "HTML バージョン : " . ($p->htmlVersion ?: 'HTML5 / 不明') . PHP_EOL;
echo "ステータス : " . match($p->status) {
0 => '✅ 正常', 1 => '⚠️ 警告', 2 => '❌ エラー', default => '不明'
} . PHP_EOL;
echo "libtidy : {$p->release}" . PHP_EOL;
echo "エラーバッファ : " . ($p->errorBuffer ?: '(なし)') . PHP_EOL;
}
}
$profiler = new DocumentProfiler();
$docs = [
'XML' => '<?xml version="1.0"?><root><node>値</node></root>',
'XHTML' => '<?xml version="1.0"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title>X</title></head><body><p>XHTML</p></body></html>',
'HTML5' => '<!DOCTYPE html><html><head><title>H5</title></head><body><p>HTML5</p></body></html>',
];
foreach ($docs as $label => $source) {
echo PHP_EOL . "【{$label}】" . PHP_EOL;
$profiler->print($profiler->profile($source));
}
出力例:
【XML】
=== ドキュメントプロファイル ===
種別 : XML
isXml() : true
isXhtml() : false
HTML バージョン : HTML5 / 不明
ステータス : ✅ 正常
libtidy : 1st August 2023
エラーバッファ : (なし)
【XHTML】
=== ドキュメントプロファイル ===
種別 : XHTML
isXml() : false
isXhtml() : true
HTML バージョン : HTML5 / 不明
ステータス : ✅ 正常
libtidy : 1st August 2023
エラーバッファ : (なし)
【HTML5】
=== ドキュメントプロファイル ===
種別 : HTML / その他
isXml() : false
isXhtml() : false
HTML バージョン : HTML5 / 不明
ステータス : ✅ 正常
libtidy : 1st August 2023
エラーバッファ : (なし)
7. 関連関数との比較
| 関数名 | 用途 | 戻り値 |
|---|---|---|
tidy_is_xml() | 入力が XML かを判定 | bool |
tidy_is_xhtml() | 入力が XHTML かを判定 | bool |
tidy_get_html_ver() | HTML バージョン番号を取得 | int |
tidy_get_status() | 解析ステータスを取得 | int |
tidy_getopt() | output-xml 等のオプション現在値を取得 | mixed |
tidy_get_output() | 整形済みドキュメントを文字列で取得 | string |
混同しやすいポイント:
tidy_is_xml()は入力の種別判定であり、tidy_getopt($tidy, 'output-xml')は出力形式の設定値です。またtidy_is_xml()とtidy_is_xhtml()は排他的ではなく、Tidy の内部ロジックによって独立して判定されます。
8. よくある落とし穴と注意点
① XHTML に対して tidy_is_xml() は false を返す
XHTML は XML のサブセットですが、Tidy の判定では tidy_is_xhtml() が true を返す場合、tidy_is_xml() は通常 false を返します。「XHTML は XML だから is_xml も true のはず」という思い込みは誤りです。
// XHTML ドキュメント
$tidy = tidy_parse_string($xhtmlSource, [], 'UTF8');
var_dump(tidy_is_xml($tidy)); // bool(false)
var_dump(tidy_is_xhtml($tidy)); // bool(true)
② output-xml オプションと混同しない
tidy_is_xml() は入力の種別判定、output-xml は出力形式の設定です。HTML5 入力でも output-xml=true を指定すれば XML に近い形式で出力されますが、tidy_is_xml() は false のままです。
③ XML 宣言だけでは true にならない場合がある
<?xml version="1.0"?> があっても、XHTML の DOCTYPE が続く場合は tidy_is_xhtml() が true になり、tidy_is_xml() は false になることがあります。
④ tidy_clean_repair() の前後で結果が変わることがある
修復処理によって DOCTYPE や XML 宣言が補完・変更されることがあり、判定結果が変わる場合があります。判定は tidy_parse_string() 直後、tidy_clean_repair() の前に行うのが安全です。
$tidy = tidy_parse_string($source, [], 'UTF8');
$isXml = tidy_is_xml($tidy); // cleanRepair 前に判定
tidy_clean_repair($tidy);
// この後は $isXml の値が変わっている可能性がある
9. まとめ
| 項目 | 内容 |
|---|---|
| 主な用途 | 解析済みドキュメントが XML かどうかをプログラムで判定する |
| 戻り値 | true(XML)/ false(XHTML・HTML またはその他) |
| OOP 版 | $tidy->isXml() |
| XHTML との関係 | XHTML は tidy_is_xml()=false / tidy_is_xhtml()=true |
| 混同注意 | output-xml オプション(出力形式)とは別物 |
| 判定タイミング | tidy_clean_repair() の前が安全 |
| よく使う組み合わせ | tidy_is_xhtml(), tidy_get_html_ver(), tidy_get_status(), tidy_getopt() |
tidy_is_xml() は tidy_is_xhtml() と対になる関数で、HTML・XHTML・XML の3種を判別する際の核心となります。「XHTML は XML だから両方 true」という誤解を避け、Tidy が独立した基準で判定することを理解した上で、ドキュメントルーティングや出力形式の自動選択に活用してください。
