• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:DBの値を基にliにulをネストしたリスト作成)

DBの値を基にliにulをネストしたリスト作成

このQ&Aのポイント
  • DBの値を利用して、liにulをネストしたリストを作成する方法を教えてください。
  • 指定されたデータベースのサンプルを元に、liにulをネストしたリストを作成する方法を詳細に教えてください。
  • データベースから取得した値を使用して、liにulをネストしたリストを作成する方法を教えてください。

質問者が選んだベストアンサー

  • ベストアンサー
  • yuu_x
  • ベストアンサー率52% (106/202)
回答No.4

>> 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);

iroha_168
質問者

補足

ご回答ありがとうございます。 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> 以上、よろしくお願いします。

その他の回答 (4)

  • yuu_x
  • ベストアンサー率52% (106/202)
回答No.5

> Fatal error: Call to undefined function fetch_assoc() w 単なるタイポ fetch_assoc() ⇒ mysql_fetch_assoc()

iroha_168
質問者

お礼

ご回答ありがとうございます。 ご指摘の点を修正した所、動作しているように見受けられました。 このたびはどうもありがとうございました。 以上、よろしくお願いします。

回答No.3

先に、すべての値を一緒にするのではなくて、ある階層ごとに、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(); } ?> 一度取得した内容をさらに別の配列に挿入して順番にサーチして、をくり返してしまうので、 取得する情報が多くなると、動作が非常に重たくなると思いますが・・・

iroha_168
質問者

お礼

ご回答ありがとうございます。 ご教示いただいたソースを試したところ、動作しているように見受けられました。 【ソース】 <!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)
回答No.2

$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);

iroha_168
質問者

補足

ご回答ありがとうございます。 ご教示いただいたソースを参考に下記のように記述した所、下記のエラーが出てしまいました。 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)
回答No.1

既に多次元配列になってるのを再帰関数で処理するのはできても、階層数不明の多次元配列をつくるのは結構難しいです。 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) ;

iroha_168
質問者

補足

ご回答ありがとうございます。 ご教示いただいたソースを試したところ、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> 以上、よろしくお願いします。

関連するQ&A

専門家に質問してみよう