- ベストアンサー
DBの値を基にliにulをネストしたリスト作成
- DBの値を利用して、liにulをネストしたリストを作成する方法を教えてください。
- 指定されたデータベースのサンプルを元に、liにulをネストしたリストを作成する方法を詳細に教えてください。
- データベースから取得した値を使用して、liにulをネストしたリストを作成する方法を教えてください。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
>> 1 ワイルドカードは カラムリストの先頭のみ。 >> 2 クロージャが使えるのは PHP 5.3 以降 $result = mysql_query('SELECT * FROM `sample_db` ORDER BY path'); $p = 0; while ($row = fetch_assoc($result)) { $depth = substr_count($row['path'], '.') - 1; if ($p != $depth) { echo $depth > $p ? '<ul>' : str_repeat("</li></ul></li>", $p - $depth); $p = $depth; } else { echo "</li>"; } echo "<li>{$row['name']}"; } echo str_repeat('</li></ul>', $p);
その他の回答 (4)
- yuu_x
- ベストアンサー率52% (106/202)
> Fatal error: Call to undefined function fetch_assoc() w 単なるタイポ fetch_assoc() ⇒ mysql_fetch_assoc()
お礼
ご回答ありがとうございます。 ご指摘の点を修正した所、動作しているように見受けられました。 このたびはどうもありがとうございました。 以上、よろしくお願いします。
- hogehoge78
- ベストアンサー率80% (433/539)
先に、すべての値を一緒にするのではなくて、ある階層ごとに、indexを分けた配列を作りなおしてから処理してしまえばある程度処理は分かりやすくなるのではないでしょうか。 <?php //下記、$rowsの中身は、mysqlが返す値すべてを含む配列としてください。 $list = array(); foreach($rows as $row){ $path = substr_count($row['path'], '.') - 2; $list[$path][] = $row; } get_ul($list[0]); function get_ul($list){ echo '<ul>' . PHP_EOL; foreach($list as $data){ echo '<li>' . PHP_EOL; echo $data['name']; $children = get_children($data['path']); if($children) get_ul($children); echo '</li>' . PHP_EOL; } echo '</ul>' . PHP_EOL; } function get_children($path){ global $list; $depth = (substr_count($path, '.') - 2) + 1; if(isset($list[$depth])){ $results = array(); foreach($list[$depth] as $data){ if(strpos($data['path'], $path) === 0){ $results[] = $data; } } return $results; } return array(); } ?> 一度取得した内容をさらに別の配列に挿入して順番にサーチして、をくり返してしまうので、 取得する情報が多くなると、動作が非常に重たくなると思いますが・・・
お礼
ご回答ありがとうございます。 ご教示いただいたソースを試したところ、動作しているように見受けられました。 【ソース】 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>タイトル</title> </head> <body> <?php $link = mysql_connect('localhost', 'データベースユーザ名', 'データベースパスワード名'); mysql_select_db('データベース名', $link); $query = mysql_query("SELECT * FROM sample_db", $link); $rows = array(); while ($row = mysql_fetch_array($query)) { $rows[] = $row; } $list = array(); foreach($rows as $row){ $path = substr_count($row['path'], '.') - 2; $list[$path][] = $row; } get_ul($list[0]); function get_ul($list){ echo '<ul>' . PHP_EOL; foreach($list as $data){ echo '<li>' . PHP_EOL; echo $data['name']; $children = get_children($data['path']); if($children) get_ul($children); echo '</li>' . PHP_EOL; } echo '</ul>' . PHP_EOL; } function get_children($path){ global $list; $depth = (substr_count($path, '.') - 2) + 1; if(isset($list[$depth])){ $results = array(); foreach($list[$depth] as $data){ if(strpos($data['path'], $path) === 0){ $results[] = $data; } } return $results; } return array(); } mysql_close($link); ?> </body> </html> 一度ソース、及びデータベースに格納されると思われる情報を検討のうえ、採否を検討させていただきたいと思います。 このたびはどうもありがとうございました。 以上、よろしくお願いします。
- yuu_x
- ベストアンサー率52% (106/202)
$result = $mysql->query("SELECT * FROM `sample_db`;"); $rem = $result->fetchAll(); function rem_to_ul($rem, $depth=1, $parent_id=null) { $p = array_filter($rem, function($v) use ($depth) { return substr_count($v['path'], '.') == ($depth + 1); }); foreach ($p as $a) { echo '<ul>'; echo "<li>{$a['name']}"; $parent_id = $a['id']; $c = array_filter($rem, function($v) use ($parent_id) { return strpos($v['path'], $parent_id) !== false; }); if (count($c)>1) rem_to_ary($c, $depth+1, $parent_id); echo '</li>'; echo '</ul>'; } } rem_to_ary($rem);
補足
ご回答ありがとうございます。 ご教示いただいたソースを参考に下記のように記述した所、下記のエラーが出てしまいました。 Parse error: parse error in ファイルのパス on line 19 どうも「$rem, function($v) use ($depth) 」の部分でエラーが出ているようなのですが、何かお心当たりはございますか? 【ソース】 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>タイトル</title> </head> <body> <?php $link = mysql_connect('localhost', 'データベースユーザ名', 'データベースパスワード名'); mysql_select_db('データベース名', $link); $result = mysql_query("SELECT * FROM sample_db", $link); $rem = $result->fetchAll(); function rem_to_ul($rem, $depth=1, $parent_id=null) { $p = array_filter( $rem, function($v) use ($depth) { return substr_count($v['path'], '.') == ($depth + 1); } ); foreach ($p as $a) { echo '<ul>'; echo "<li>{$a['name']}"; $parent_id = $a['id']; $c = array_filter ($rem, function($v) use ($parent_id) { return strpos($v['path'], $parent_id) !== false; } ); if (count($c)>1) rem_to_ary($c, $depth+1, $parent_id); echo '</li>'; echo '</ul>'; } } rem_to_ary($rem); mysql_close($link); ?> </body> </html> 以上、よろしくお願いします。
- mpro-gram
- ベストアンサー率74% (170/228)
既に多次元配列になってるのを再帰関数で処理するのはできても、階層数不明の多次元配列をつくるのは結構難しいです。 tableのデータ構成は、前回紹介した経路列挙モデルですね。階層レベルの割り出しは以下のSQL文でできますので、階層レベルをチェックしながら、開始終了タグ出力を制御するのがよいかと思います。 <?php $sql = <<<SSS SELECT LENGTH(path) - LENGTH(REPLACE(path,'.','')) -1 AS depth , * FROM `sample_db` ORDER BY path SSS; /* ORDER BY path は重要。並び順を指定しておかないと、順不定になり、入れ子にならなくなります。 */ $query = mysql_query($sql, $link); $p = 0; /* ul出力カウンタ: 初期値 0 : depthをrootのとき 1 開始になるようにしておく */ while ($row = mysql_fetch_array($query)) { $starter= "\n"; $rp = intval( $row['depth'] ); /* 自分までの階層レベル:念のため数値変換 */ // ↓ 階層レベルチェック: if( $p< $rp ){ // 子の開始 $p ++; $starter .= "<ul id='ul_{$row[1]}'><li>"; }else { if( ($dp= $p-$rp) >0 ){ // 前の 子の終了: </ul> をstarterに入れて閉じる $p = $rp; $starter .= str_repeat('</li></ul>', $dp); /* 2段階以上戻るのにも対応 */ } // 現在levelの開始 $starter .= '</li><li>'; } echo "$starter $row[1]: $row[2] : $row[3] "; } // 残りの階層の閉じタグ echo "\n". str_repeat('</li></ul>', $p) ;
補足
ご回答ありがとうございます。 ご教示いただいたソースを試したところ、select文のdepthの取得に問題があるようでしたが、何かお心あたりはございますか? なお、DBにdepthの値を格納した上で試した場合は動作しているように見受けられました。 【データベース】 CREATE TABLE IF NOT EXISTS `sample_db` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(64) NOT NULL, `path` varchar(255) NOT NULL, `depth` int(10) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `path` (`path`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=11 ; INSERT INTO `sample_db` (`id`, `name`, `path`, `depth`) VALUES (1, '2010年', '.1.', 1), (2, '6月', '.1.2.', 2), (3, '28日', '.1.2.3.', 3), (4, '12時', '.1.2.3.4.', 4), (5, '13時', '.1.2.3.5.', 4), (6, '29日', '.1.2.6.', 3), (7, '30日', '.1.2.7.', 3), (8, '7月', '.1.8.', 2), (9, '8月', '.1.9.', 2); 【ソースコード】 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>タイトル</title> </head> <body> <?php $link = mysql_connect('localhost', 'データベースユーザ名', 'データベースパスワード名'); mysql_select_db('データベース名', $link); $sql = <<<SSS SELECT * FROM `sample_db` ORDER BY path SSS; /* ORDER BY path は重要。並び順を指定しておかないと、順不定になり、入れ子にならなくなります。 */ $query = mysql_query($sql, $link); $p = 0;/* ul出力カウンタ: 初期値 0 : depthをrootのとき 1 開始になるようにしておく */ while ($row = mysql_fetch_array($query)) { $starter= "\n"; $rp = intval( $row['depth'] );/* 自分までの階層レベル:念のため数値変換 */ // ↓ 階層レベルチェック: if( $p< $rp ){ // 子の開始 $p ++; $starter .= "<ul id='ul_{$row[1]}'><li>"; }else { if( ($dp= $p-$rp) >0 ){ // 前の 子の終了: </ul> をstarterに入れて閉じる $p = $rp; $starter .= str_repeat('</li></ul>', $dp);/* 2段階以上戻るのにも対応 */ } // 現在levelの開始 $starter .= '</li><li>'; } echo "$starter $row[1]: $row[2] : $row[3] "; } // 残りの階層の閉じタグ echo "\n". str_repeat('</li></ul>', $p) ; mysql_close($link); ?> </body> </html> 以上、よろしくお願いします。
補足
ご回答ありがとうございます。 No.1様のソースの件ですが、ご指摘の点を修正した所、動作しているように見受けられました。 またNo.2のソースの件、了解しました。 確認した所、PHPのバージョンは5.2.9でした。 それと今回ご教示いただいたソースを試した所、下記のエラーが出ているようなのですが、何かお心当たりはございますか? Fatal error: Call to undefined function fetch_assoc() 【ソース】 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>タイトル</title> </head> <body> <?php $link = mysql_connect('localhost', 'データベースユーザ名', 'データベースパスワード名'); mysql_select_db('データベース名', $link); $result = mysql_query('SELECT * FROM `sample_db` ORDER BY path'); $p = 0; while ($row = fetch_assoc($result)) { $depth = substr_count($row['path'], '.') - 1; if ($p != $depth) { echo $depth > $p ? '<ul>' : str_repeat("</li></ul></li>", $p - $depth); $p = $depth; } else { echo "</li>"; } echo "<li>{$row['name']}"; } echo str_repeat('</li></ul>', $p); mysql_close($link); ?> </body> </html> 以上、よろしくお願いします。