<?php
/*
 * framework-spider
 * util/XMLNode.class.php
 * 
 * CopyRight(C)Framework-Spider Developer Team. 2010. All Right Reserved. 
 * URL         : http://sourceforge.jp/projects/frameworkspider/
 * Mail        : frameworkspider-dev@lists.sourceforge.jp
 * Auther      : Masanori Nakashima
 * Modifier    : Masanori Nakashima
 * Last Updated: 2010.06.23
 * 
 */
/**
 * XMLノードをオブジェクト構造として保持するクラス
 * @package util ユーティリティパッケージ
 * @version 1.0.0
 * @copyright Copyright &copy; 2008, <m_nakashima@users.sourceforge.jp> http://sourceforge.jp/projects/shopformer/
 * @author  m.nakashima <m_nakashima@users.sourceforge.jp>
 * @since PHP 4.3
 */
class util_XMLNode {
	var $elementName;
	var $attributes		= array();
	var $parentNode;
	var $childNodes		= array();
	var $contents		= '';
	function util_XMLNode() {
	}
	function parseXML( $strings ) {
		$this->childNodes	= array();
		// 最初のタグ終了までを解析
		$element_str			= '';
		$need_end_tag			= true;
		$in_element_attribute	= false;
		$after_strings			= '';
		$is_end_thisnode		= false;
		$inner_strings			= '';
		for( $i = 0; $i < strlen($strings); $i++ ) {
			$char	= substr($strings,$i,1);
			if( strlen(trim($this->elementName)) == 0 ) {
				// ルートノード名が取得できていない場合
				if( '<' == $char ) {
					$in_element_attribute	= true;
				} else if( '>' == $char ){
					$in_element_attribute	= false;
					// 要素名の決定処理
					$attributes	= explode("\s",$element_str);
					$this->elementName	= array_shift($attributes);
					// 属性の取得
					foreach( $attributes as $attribute ) {
						if( strlen( trim($attribute) ) > 1 ) {
							list( $key, $value )	= explode('=',$attribute);
							$value					= preg_replace('/^\\"/','',$value);
							$value					= preg_replace('/\\"$/','',$value);
							$this->attributes[$key]	= $value;
						}
					}
					// 最後が/で終わっているなら終了タグを必要としない
					if( $attributes[count($attributes)-1] == '/' ) {
						$need_end_tag	= false;
					}
					$element_str	= '';
				} else if( $in_element_attribute ) {
					$element_str	.= $char;
				} else {
					// 最初のルートノードが取得できるまで文字列は無視するので何もしない
				}
			} else if(!$need_end_tag) {
				// 終了タグを必要としないなら残りの文字は全て同列要素文字列
				$after_strings	.= $char;
			} else if($is_end_thisnode) {
				// 終了タグ後なら残りの文字は全て同列要素文字列
				$after_strings	.= $char;
			} else {
				// タグ内容に関わらず終了タグが来ていないなら内包文字として追加
				$inner_strings	.= $char;
				// 終了タグを必要とするなら終了タグを検索
				if( '<' == $char ) {
					$in_element_attribute	= true;
				} else if( '>' == $char ){
					$in_element_attribute	= false;
					// タグ要素名の解析
					$attributes		= explode("\s",$element_str);
					$element_name	= array_shift($attributes);
					if( '/'.$this->elementName == $element_name ) {
						// 本ノードの終了タグなら
						$is_end_thisnode	= true;
					}
					$element_str	= '';
				} else if( $in_element_attribute ) {
					$element_str	.= $char;
				}
			}
		}
		// 閉じタグがあるなら消去しておく
		if( $need_end_tag && $is_end_thisnode ) {
			$inner_strings	= str_replace('</'.$this->elementName.'>','',$inner_strings);
		}

		if( $need_end_tag && !$is_end_thisnode ) {
			// 閉じタグが必要にも関わらず終了タグが見つからなかった場合はエラー
			return false;
		}
		if( preg_match('/<(.)+>/',$inner_strings) > 0 ) {
			// 内部文字列はカラ文字列になるまで処理を繰り返す
			while( strlen(trim($inner_strings)) > 0 ) {
				$child_node	= new util_XMLNode();
				$inner_strings	= $child_node->parseXML( $inner_strings );
				if( $inner_strings === false ) {
					// 子ノードで閉じタグ不正が発覚した場合はエラー
					return false;
				} else {
					// 子ノード作成OK
					$child_node->parentNode	= & $this;
					array_push( $this->childNodes, $child_node);
				}
			}
		} else {
			$this->contents	= $inner_strings;
		}
		// 同列の残り文字列は親に処理を戻す
		return trim($after_strings);
	}
}
?>