マーク付け言語の構文解析
マーク付け言語の構文解析について。
マーク付け言語の構文解析クラス
クラスの作成経緯
XSLTプロセッサによるXSLT変換の際に、出力メソッドでインデント付けを有効にしたX/HTMLへの出力を行う場合、HTML出力メソッドであれブロック要素とインライン要素の区別を仕様上することはありません。また、出力内容が [XHTML10] の場合にメディアタイプをtext/html
と指定したとしても、HTML互換性ガイドラインで提示される方法で空要素の空タグを閉じたりもしません。そこで、変換結果のソース整形を行う為に先ずソース解析を行うこのクラスを作成しました。
私が作成した ML Parser は、PHPの拡張ライブラリ・XMLパーサ関数とは異なり、SGML/XML両構造化文書に対応しています。ですから、SGMLベースのHTMLやXMLベースのXHTMLの文書解析も勿論行えます。
MLParser
クラス
public class MLParser extends Object
構造
- PHP 5
markup/MLParser.php
コンストラクタ
public void MLParser([String $encoding])
- マーク付け言語の構文解析を行います。
- 引数
String $encoding
- 出力のエンコーディング名(省略化)。mbstringモジュールがサポートする文字エンコーディングのみ指定できます。
メソッド
public void setSAXHandler(Object $handler)
- 文書解析ハンドラのメソッドを設定する。
- 引数
Object $handler
- オブジェクト指向ハンドラ
public void setDocumentHandler(callback $startHandler, callback $endHandler)
- 文書のハンドラを設定する。
- 引数
callback $startHandler
- 開始ハンドラ関数
callback $endHandler
- 終了ハンドラ関数
public void setDTDHandler(callback $handler)
- 文書型宣言(DTD)のハンドラを設定する。
- 引数
callback $handler
- ハンドラ関数
public void setPIHandler(callback $handler)
- 処理命令(PIs)のハンドラを設定する。
- 引数
callback $handler
- ハンドラ関数
public void setCommentHandler(callback $handler)
- コメントのハンドラを設定する。
- 引数
callback $handler
- ハンドラ関数
public void setElementHandler(callback $startHandler, callback $endHandler)
- 要素の開始タグおよび終了タグのハンドラを設定する。
- 引数
callback $startHandler
- 開始ハンドラ関数
callback $endHandler
- 終了ハンドラ関数
public void setCharactersHandler(callback $handler)
- 文字データのハンドラを設定する。
- 引数
callback $handler
- ハンドラ関数
public void setCDATASectionHandler(callback $handler)
- CDATAセクションのハンドラを設定する。
- 引数
callback $handler
- ハンドラ関数
public void setMarkedSectionHandler(callback $handler)
- SGMLのマーク区間のハンドラを設定する。
- 引数
callback $handler
- ハンドラ関数
public void setDefaultHandler(callback $handler)
- デフォルトのハンドラを設定する。
- 引数
callback $handler
- ハンドラ関数
public void addPreserveSpace(String $name [, ...])
- 空白文字を保持する要素の設定を追加する(幾つでも指定可)。未設定の場合には、SGMLでは全ての要素で非保持、XMLでは
xml:space
属性を解釈(属性が未宣言及び値が'preserve
'ならば保持、'default
'ならば非保持)します。 - 引数
String $name
- 要素型
public void addEmptyElements(String $name [, ...])
- SGMLの空の要素型の設定を追加する(幾つでも指定可)。
- 引数
String $name
- 要素型
public Integer getCurrentLine()
- 現在の行番号を取得する。
- 返り値
- 行番号
public Integer getCurrentPosition()
- 現在の文字位置を取得する。
- 返り値
- 文字位置
public String getNamespaceToElement(String $qname)
- 要素の名前空間を取得する。(これはXML用のメソッドです。名前空間に対応したXML文書でのみ取得可能です。)
- 引数
String $qname
QName
- 返り値
- URI
public String getNamespaceToAttribute(String $qname)
- 属性の名前空間を取得する。(これはXML用のメソッドです。名前空間に対応したXML文書でのみ取得可能です。)
- 引数
String $qname
QName
- 返り値
- URI
public void parse(String $source [, Integer $markup])
- 文書の処理を開始する。
- 引数
String $source
- 処理する文書データ
Integer $markup
- 処理する文書データのマーク付け言語の種類 [
MLPARSER_PARSE_SGML
|MLPARSER_PARSE_XML
]
クラスの使用例
次の例は、MLParser
クラスを使用したサンプルです。
<?php
ini_set("include_path", "./");
// require_once("org/purl/net/osamurai/markup/MLParser.php"); // for PHP 4
require_once("markup/MLParser.php"); // for PHP 5
$filename = "data.xml";
$level = 0;
function startElement($name, $attrs) {
global $level;
for ($i=0; $i<$level; $i++) {
print " ";
}
print "{$name}\n";
$level++;
}
function endElement($name) {
global $level;
$level--;
}
$handle = fopen($filename, "r");
$contents = fread($handle, filesize($filename));
fclose($handle);
$parser = new MLParser;
$parser->setElementHandler('startElement', 'endElement');
$parser->parse($contents, MLPARSER_PARSE_XML);
unset($parser);
?>
上の例では、XML文書の構文を解析し、要素の構造をインデントを付けて表示します。これと同様の処理をHTML等のSGML関連規格でマーク付けされた文書に行う場合には、次のように記述を一部変更(及び追加)すると良い。
...
$parser = new MLParser;
$parser->setElementHandler('startElement', 'endElement');
// HTML 4.01 Strict DTD
$parser->addPreserveSpace("pre");
$parser->addEmptyElements("area", "base", "br", "col", "hr",
"img", "input", "link", "meta", "param");
// HTML 4.01 Transitional DTD
//$parser->addEmptyElements("basefont", "isindex");
// HTML 4.01 Frameset DTD
//$parser->addEmptyElements("frame");
$parser->parse($contents, MLPARSER_PARSE_SGML);
...
注釈
- 以前のPHP4用のソースコードでは、処理時の内部表現は、常に定数'
MLPARSER_INTERNAL_ENCODING
'の文字エンコーディング名でエンコードされます。後継版のPHP5用では、ソースエンコーディング(出力)及びターゲットエンコーディング(入力)の際にエンコーディングを行う仕組みに改善・修正しました。 - 構文解析の際にDTDの解析は行いません。また、[XML11] は考慮していません。
- SGMLの構文解析では、要素の省略化マーク付け(短縮タグ機構)には対応していません。他にも、処理命令
<?experiment> ... <?/experiment>
の書式にも対応していません。 - ご利用の際の注意事項などもご覧下さい。
SAXHandler
インターフェイス
public interface SAXHandler extends Object
構造
メソッド
public void startDocument()
- 文書のハンドラ(開始)
public void endDocument()
- 文書のハンドラ(終了)
public void documentTypeDefinition(String $doctypedecl)
- 文書型宣言のハンドラ
- 引数
String $doctypedecl
- 文書型宣言
public void processingInstruction(String $target, String $data)
- 処理命令のハンドラ
- 引数
String $target
- PIのターゲット
String $data
- PIの内容
public void comment(String $data)
- 注釈のハンドラ
- 引数
String $data
- コメントの内容
public void startElement(String $name, Array $atts)
- 要素のハンドラ(開始タグ)
- 引数
String $name
- 要素型
Array $atts
- 属性指定 [
array([属性名 => 属性値 [, ...]])
]
public void endElement(String $name)
- 要素のハンドラ(終了タグ)
- 引数
String $name
- 要素型
public void characters(String $data)
- 文字列のハンドラ
- 引数
String $data
- 文字列
public void cdataSection(String $cdsect)
- CDATAセクションのハンドラ
- 引数
String $cdsect
- CDATAセクション
public void markedSection(String $markedsect)
- マーク区間のハンドラ
- 引数
String $markedsect
- マーク区間
public void defaultHandler(String $data)
- デフォルトのハンドラ
- 引数
String $data
- 文字列
サンプル
概要
マーク付け言語の構文解析クラスの処理の際にコールするSAXHandler
インターフェイスを実装したハンドラのサンプルです。取り敢えず、オブジェクト指向ハンドラのサンプルとして、本サイトで「ソース整形(改行と字下げ)」に使用しているハンドラを公開します。
ちなみに、本サイトのソース(XSLT変換結果の出力)の改行と字下げ付けは、処理時間を短縮するためにデフォルトでは無効にしています。ソースを綺麗にして読みたい方は、各種設定(或いは、URIにindent=on
というクエリーを付与)にてインデント機能を有効に変更されてください。一応、出力がXHTMLの場合には、媒体型により内容モデルの処理方法が異なります。
構造
ハンドラの使用例
次の例は、ソース整形(改行と字下げ)ハンドラを使用したサンプルです。
<?php
ini_set("include_path", "./");
/*
// for PHP 4
require_once("org/purl/net/osamurai/markup/MLParser.php");
require_once("org/purl/net/osamurai/markup/IndentHandler.php");
*/
// for PHP 5
require_once("markup/MLParser.php");
require_once("markup/IndentHandler.php");
$filename = "data.xml";
$handle = fopen($filename, "r");
$contents = fread($handle, filesize($filename));
fclose($handle);
$parser = new MLParser;
$handler = new IndentHandler(&$parser);
$handler->setMinimize(INDENTHANDLER_MINIMIZE_EMPTY_ELEMENTS);
$parser->setSAXHandler($handler);
$parser->parse($contents, MLPARSER_PARSE_XML);
unset($parser, $handler);
?>
注釈
- サンプルにて利用できるメソッド等については、ファイル中の注釈をご覧下さい。