以前GoogleNotebook解析のためにどんな感じでSAXで読むんだろ?って書いたものの続編。
<?php require_once 'XML/XML_HTMLSax.php'; class MyHandler{ var $elements; function MyHandler() { $this->elements = array(); } /** * 要素を開いた段階でその情報(要素の属性と名前)を * 連想配列に突っ込む。 * @todo その際に属性がidやclassなどの重要なもの以外は * 全て削除しても良いのではないか。 */ function openHandler( &$parser, $name, $attrs ) { array_push($this->elements, array($name=>$attrs)); } /** * 要素を閉じるときにその直前の内容を保持している配列から * 処理済である末尾の要素を削除する */ function closeHandler( &$parser, $name ) { array_pop($this->elements); } /** * テキストノードの解釈。 * 自分自身が現在どこを処理対象としているかで各関数の * 判定を行い、その判定が正しければ内容を出力 */ function dataHandler( &$parser, $data ) { // 期待する構造のあるデータが取得できたら出力 if($this->_getSomeTextNode()){ echo $data; } } /** * 連想配列形式で指定したHTMLのノードが含まれるかどうかを返す * 取得したいノードごとに$expectedArrayを作る * おそらくもう少し「ゆるい」指定にしないとキツいか・・・ * 多分、idとかしか使わないだろう・・・ * @see openHandler */ function _getSomeTextNode() { $expectedArray = array( array('root' => array()), array('element' => array( 'attr' => 'test', 'id' => 'second' ) ) ); return $this->_isValidArray($this->elements, $expectedArray); } /** * 二つの連想配列がデータとして等しいかどうかを返す * @todo 多分serializeしたものを小文字で比較した方が良い */ function _isValidArray($inputArray, $expectedArray) { /** * Example * $expectedArray = array( * array('root' => array()), * array('element' => array('attr' => 'test', 'id' => 'second')) * ); */ return $inputArray === $expectedArray; } } // Parsing $handler = new MyHandler(); $parser =& new XML_HTMLSax(); $parser->set_object($handler); $parser->set_option('XML_OPTION_TRIM_DATA_NODES'); // handlers $parser->set_element_handler('openHandler', 'closeHandler'); $parser->set_data_handler('dataHandler'); //$contents = file_get_contents("googlenote.html"); $contents = <<<DOC <root> <element id="first" attr="attribute"> <child>text</child> </element> <element attr="test" id="second"> textnode </element> AAAAAAAAAAAAAAAAA </root> DOC; $parser->parse($contents); ?>
なにかこう、ものすごくbrとかの「閉じてないタグ」が問題を引き起こしていることに気づいた。