何でも使えるツリー構造を定義する
いろいろな場面でツリー構造が必要になるので(たとえばACL機能、ユーザーファイル保存機能etc...)ツリー構造クラスを作った。
class TreeNode{ var $parent; var $children = array(); var $name; var $object; public function __construct($name = ""){ $this->name = $name; } public function appendChild(TreeNode $node){ $this->children[$node->name] = $node; $node->parent = $this; } public function removeChilde(TreeNode $node){ unset($this->children[$node->name]); $node->parent = null; } /** * このオブジェクトが指定ノードの先祖かどうか * @param unknown_type $node * @return unknown_type */ public function isAncestorOf($node){ $result = false; $p = $node->parent; while($p != null){ if($this->name == $p->name){ $result = true; break; } $p = $p->parent; } return $result; } /** * このオブジェクトが指定ノードの子孫かどうか * @param unknown_type $node * @return unknown_type */ public function isDescendantOf($node){ return $node->isAncestorOf($this); } public function pathString(){ $path = $this->path(); $result =join("/",$path); return $result; } public function path(){ $result = array($this->name); $p = $this->parent; while($p != null){ $result[] = $p->name; $p = $p->parent; } return array_reverse($result); } public function find($path = array()){ $target = null; $count = count($path); $current = $this; for($depth = 0;$depth < $count;$depth++){ //現在のノードの子供に対象パスが見つかったらその子供を次のノードに設定する if(array_key_exists($path[$depth],$current->children)){ $current = $current->children[$path[$depth]]; //現在のノードを発見 $target = $current; continue; } //見つからない break; } return $target; } }
データの追加はこんな感じ
$tree = new TreeNode(""); //root node $node1 = new TreeNode("node1"); $tree->appendChild($node1); $node2 = new TreeNode("node2"); $tree->appendChild($node2); $node3 = new TreeNode("node3"); $tree->appendChild($node3); $node1_1 = new TreeNode("node1_1"); $node1->appendChild($node1_1); $node1_2 = new TreeNode("node1_2"); $node1->appendChild($node1_2); $node1_3 = new TreeNode("node1_3"); $node1->appendChild($node1_3); $node1_4 = new TreeNode("node1_4"); $node1->appendChild($node1_4); $node2_1 = new TreeNode("node2_1"); $node2->appendChild($node2_1); $node2_2 = new TreeNode("node2_2"); $node2->appendChild($node2_2); $node2_3 = new TreeNode("node2_3"); $node2->appendChild($node2_3); $node2_1_1 = new TreeNode("node2_1_1"); $node2_1->appendChild($node2_1_1); $node2_1_2 = new TreeNode("node2_1_2"); $node2_1->appendChild($node2_1_2); $node2_1_3 = new TreeNode("node2_1_3"); $node2_1->appendChild($node2_1_3);
この結果はこんな感じ
node1 : Array node1_1 : Array node1_2 : Array node1_3 : Array node1_4 : Array node2 : Array node2_1 : Array node2_1_1 : Array node2_1_2 : Array node2_1_3 : Array node2_2 : Array node2_3 : Array node3 : Array
特定ノードを探すなら
$result = $tree->find(array("node2","node2_1","node2_1_1"); //$node2_1_1が見つかる
特定ノード以下から探すなら
$result = $node2_1->find(array("node2_1_1"); //$node2_1_1が見つかる
用はxpath見たいな感じで、現在ノード以下でその名前を持ったノードを探す、という。
path()で対象ノードの「パス」を配列で返し、pathString()で「パス」をスラッシュ区切りで返す。
たぶんC#でもjavascriptでもActionScriptでも同じに書けるはず。
データのロード、セーブは別途。