青空文庫のXMLは仕様通りにキッチリ書いてあるものと、そうでないものがあり、ちょっと苦労した。
以下のクラスは基本的に「大見出し」と「中見出し」で区切って配列にして返すものだけど、面倒な処理は正規表現やexplodeでばっさり切り分けたりしてます。
---
このクラスを使って小説を転載したものは、以下のサイトで読めます。
・多賀城[たがのき]小説投稿サイト
良かったら見てくださいませ。
---
/*
* 青空文庫XMLパーサ
* 2013/10/01
*/
class Aozora
{
const FROM_ENCODING = 'sjis-win';
const TO_ENCODING = 'UTF-8';
public $filename;
public $title;
public $author;
/*
本文の階層構造
大見出しがある場合
bodies = array(
'大見出し_01' => array( '中見出し_01' => '本文', '中見出し_02' => '本文', ... '中見出し_nn' => '本文' ),
'大見出し_02' => array( '中見出し_01' => '本文', '中見出し_02' => '本文', ... '中見出し_nn' => '本文' ),
'大見出し_03' => array( '中見出し_01' => '本文', '中見出し_02' => '本文', ... '中見出し_nn' => '本文' ),
...
'大見出し_nn' => array( '中見出し_01' => '本文', '中見出し_02' => '本文', ... '中見出し_nn' => '本文' ) );
大見出しが無い場合
bodies = array( '中見出し_01' => '本文', '中見出し_02' => '本文', ... '中見出し_nn' => '本文' );
*/
public $bodies;
public $infomation; // 小説情報
public $notes; // 注
public $is_omidasi;
public $is_tyumidasi;
private $raw_text;
private $main_text;
private $biblio;
public function __construct( $filename )
{
$this->filename = $filename;
$this->raw_text = file_get_contents( $this->filename );
$this->raw_text = mb_convert_encoding( $this->raw_text, self::TO_ENCODING, self::FROM_ENCODING );
$this->bodies = array();
}
public function get_title()
{
return sprintf( '%s (作者:%s)', $this->title, $this->author );
}
public function get_bodies()
{
return $this->bodies;
}
/**
XMLパース本体
*/
public function parse()
{
// 改行を全て消す
$this->raw_text = preg_replace( '#[\n\r]+#i', '', $this->raw_text );
$this->raw_text = preg_replace( '#[\s]+#i', ' ', $this->raw_text );
// タイトルと著者を取得する
$ret = preg_match( '#(.*?)
#i', $this->raw_text, $temp_text );
$this->title = $this->replace_imgtag( $temp_text[ 1 ] );
$this->title = trim( $this->title );
$ret = preg_match( '#(.*?)
#i', $this->raw_text, $temp_text );
$this->author = $this->replace_imgtag( $temp_text[ 1 ] );
$this->author = trim( $this->author );
// 付加情報を取得する
$ret = preg_match( '#(.*?)#i', $this->raw_text, $temp_text );
$this->infomation = $this->remove_htmltag( $temp_text[ 1 ] );
$this->infomation = $this->add_return( $this->infomation );
$this->infomation = trim( $this->infomation );
// 本文を全て取得する
$ret = preg_match( '#(.*)#i', $this->raw_text, $temp_text );
$this->main_text = trim( $temp_text[ 1 ] );
// 大見出しから切り出し
$this->parse_omidasi();
}
/*
大見出しがある場合の本文切り出し
*/
private function parse_omidasi()
{
if( $this->is_omidasi( $this->main_text ) ) {
// 大見出しがある場合
$temp_text = explode( '', $this->main_text );
foreach( $temp_text AS $temp ) {
if( trim( $temp ) == "" ) { continue; }
if( !$this->is_omidasi( $temp ) ) { continue; }
$ret = preg_match( '#(.*?)
(.*)$#', $temp, $temp_omidasi );
$omidasi = $this->remove_htmltag( $temp_omidasi[ 1 ] );
$omidasi = $this->replace_imgtag( $omidasi );
$omidasi = trim( $omidasi );
$this->bodies[ $omidasi ] = $this->parse_tyumidasi( $temp_omidasi[ 2 ] );
}
} else {
// 大見出しがない場合
$this->bodies[] = $this->parse_tyumidasi( $this->main_text );
}
}
/*
中見出しから本文切り出し
@param $html 大見出し1つ分のテキスト または 本文全体のテキスト
*/
private function parse_tyumidasi( $html )
{
$tyumidasi_array = array();
if( $this->is_tyumidasi( $html ) ) {
$temp_text = explode( '', $html );
foreach( $temp_text AS $idx => $temp ) {
if( trim( $temp ) == "" ) { continue; }
if( !$this->is_tyumidasi( $temp ) ) { continue; }
$ret = preg_match( '#(.*?)
(.*)$#', $temp, $temp_tyumidasi );
$tyumidasi = $this->remove_htmltag( $temp_tyumidasi[ 1 ] );
$tyumidasi = $this->replace_imgtag( $tyumidasi );
$tyumidasi = trim( $tyumidasi );
$tyumidasi_array[ $tyumidasi ] = $this->remove_htmltag( $temp_tyumidasi[ 2 ] );
$tyumidasi_array[ $tyumidasi ] = $this->replace_imgtag( $tyumidasi_array[ $tyumidasi ] );
$tyumidasi_array[ $tyumidasi ] = $this->add_return( $tyumidasi_array[ $tyumidasi ] );
}
} else {
$tyumidasi_array[ 1 ] = $this->remove_htmltag( $html );
$tyumidasi_array[ 1 ] = $this->replace_imgtag( $tyumidasi_array[ 1 ] );
$tyumidasi_array[ 1 ] = $this->add_return( $tyumidasi_array[ 1 ] );
}
return $tyumidasi_array;
}
/*
大見出しがあるかどうか
*/
private function is_omidasi( $html )
{
$ret = substr_count( $html, '' );
if( $ret > 0 ) {
$this->is_omidasi = true;
} else {
$this->is_omidasi = false;
}
return $this->is_omidasi;
}
/*
中見出しがあるかどうか
*/
private function is_tyumidasi( $html )
{
$ret = substr_count( $html, '' );
if( $ret > 0 ) {
$this->is_tyumidasi = true;
} else {
$this->is_tyumidasi = false;
}
return $this->is_tyumidasi;
}
/*
余分なHTMLタグを除去する
*/
private function remove_htmltag( $text )
{
return preg_replace( '#<(?:|/)(?:em|div|span|a|h3|h4|hr)[^>]*>#', '', $text );
}
/*
画像タグを置き換える
*/
private function replace_imgtag( $text )
{
return preg_replace( '#
]+>#', "$1", $text );
}
/*
* 改行を元に戻す
*/
private function add_return( $text )
{
return preg_replace( '#
]+>#', "\r\n", $text );
}
}
以上です。
