PHPの組み込み関数にもXMLをパースする関数があるけど、自分で実装したくなったので自分で書いてみたよ。
APIから返されるXMLの構造が微妙に難しかったので、再帰関数とスタックでやってみた。
APIのURLは→「http://webservice.d-064.com/3.x/category.xml」です。
/**
電脳卸用全てのカテゴリをパースして配列して、シリアライズ後保存する。
パース結果の配列は以下のような仕様で出力される
結果配列仕様:
array( 'カテゴリID 1' => array( 'name' => 'カテゴリ名', 'parent' => '親カテゴリID' ) );
array( 'カテゴリID 2' => array( 'name' => 'カテゴリ名', 'parent' => '親カテゴリID' ) );
array( 'カテゴリID 3' => array( 'name' => 'カテゴリ名', 'parent' => '親カテゴリID' ) );
...
array( 'カテゴリID n' => array( 'name' => 'カテゴリ名', 'parent' => '親カテゴリID' ) );
※一番上のカテゴリは親カテゴリIDが「-1」となっている。
商品のカテゴリIDから親カテゴリ全てを取得するには、
function get_category_tree( $category_id, &$category_tree )
{
global $global_category_array;
$id = $category_id;
$name = $global_category_array[ $id ][ 'name' ];
$parent = $global_category_array[ $id ][ 'parent' ];
$category_tree[ $id ] =
array( 'name' => $name, 'parent' => $parent );
if( $parent == '-1' ) {
return ;
} else {
get_category_tree( $parent, $category_tree );
}
}
$global_category_array = unserialize( file_get_contents( './category_array.dat' ) );
$tree = array();
get_category_tree( '1269', $tree );
var_dump( $tree );
といったプログラムで返せる。
*/
define( 'CATEGORY_XML_URL', 'http://webservice.d-064.com/3.x/category.xml' );
define( 'CATEGORY_XML_FILENAME', dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'category.xml' );
define( 'CATEGORY_ARRAY_FILENAME', dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'category_array.dat' );
define( 'CATEGORY_SRC_ENCODING', 'UTF-8' );
define( 'CATEGORY_DIST_ENCODING', 'SJIS' );
date_default_timezone_set( 'Asia/Tokyo' );
/*
個々のカテゴリデータを取得する
@return array [ 'category_id', 'category_depth', 'category_name' ]
*/
function get_id_depth_name()
{
global $xmlp;
return array(
preg_replace( '/<[^>]+>(.*?)<\/[^>]+>/', '$1', trim( fgets( $xmlp ) ) ), // カテゴリID
preg_replace( '/<[^>]+>(.*?)<\/[^>]+>/', '$1', trim( fgets( $xmlp ) ) ), // カテゴリ深さ
preg_replace( '/<[^>]+>(.*?)<\/[^>]+>/', '$1', trim( fgets( $xmlp ) ) ) ); // カテゴリ名
}
/**
カテゴリXMLをパースする。再帰関数。
@param $parent 親カテゴリID
*/
function parse( $parent = -1 )
{
global $xmlp;
global $global_category_array;
global $global_parent_ids; // 親IDのスタック
$line = trim( fgets( $xmlp ) );
switch( true ) {
// 空行
case ($line == ''):
parse( $parent );
break;
// XML定義
case preg_match( '/<\?xml(?:[^>]+)>/', $line ):
parse( $parent );
break;
// 一番外側のタグ
case ($line == ''):
parse( $parent );
break;
case ($line == ' '):
fclose( $xmlp );
return;
// 1つのカテゴリ
case ($line == ''):
list( $id, $depth, $name ) = get_id_depth_name();
$name = mb_convert_encoding( $name, CATEGORY_DIST_ENCODING, CATEGORY_SRC_ENCODING );
// 親IDを退避
$parent = $global_parent_ids[ 0 ];
// スタックに自分を積む
array_unshift( $global_parent_ids, $id );
$global_category_array[ $id ][ 'name' ] = $name;
$global_category_array[ $id ][ 'parent' ] = $parent;
parse( $parent );
break;
case ($line == ' '):
// 自分のIDを捨てる
array_shift( $global_parent_ids );
parse( $global_parent_ids[ 0 ] );
break;
// サブカテゴリ
case ($line == ''):
parse( $global_parent_ids[ 0 ] );
break;
case ($line == ' '):
parse( $global_parent_ids[ 0 ] );
break;
// ファイルが終わる前に「/Categorys」が来るはずなので使わないかも。
case feof( $xmlp ):
fclose( $xmlp );
return;
// 何かあったときのための保険。そのまま終了。
default:
die( '[' . $line . '] Exception.' );
}
}
// XMLファイルダウンロードと保存
file_put_contents( CATEGORY_XML_FILENAME, file_get_contents( CATEGORY_XML_URL ) );
// XMLファイルのポインタ取得
$xmlp = fopen( CATEGORY_XML_FILENAME, 'r' );
if( !$xmlp ) {
die( 'XML File Dont Open.' );
}
// 親IDスタックと結果配列準備
$global_parent_ids = array( -1 );
$global_category_array = array();
// パース本体
parse();
// 結果配列をシリアライズして保存
file_put_contents( CATEGORY_ARRAY_FILENAME, serialize( $global_category_array ) );
exit( 0 );
こんな感じ。
