如何从数据创建分层列表
How to create a hierarchical list from data
对于 PHP,我需要创建一个三层深度的导航栏。我有这样的数据:
我需要这样组织它:
Napkins
--Colored Napkins
----American Tradition
--White Beverage Napkins
----American Digital
----American Tradition
----American Hi-Speed
--White Luncheon Napkins
----American Digital
----American Tradition
----American Hi-Speed
--White Dinner Napkins
...(etc)...
Plates
--Eco-Plates
----American Tradition
--Plastic Trays
...(etc)...
只是使用相对简单的 <ul>
结构,其中包含 <li>
和 <a>
。显然需要一个循环来遍历数据行。而且我知道我需要做很多 "testing" 来查看 "current" category/subcategory/method 是否与上一次循环迭代中的匹配。
但是我无法让 <ul> and <li>
标签在正确的位置关闭并且 不显示 打印方法层只有 one 给定 category/subcategory 的打印方法。或者当有无打印方式时(有时可以是null
,比如塑料器具)。我该如何设置?
编辑
我目前的代码几乎可以工作,但是非常笨拙($items
是数据库中的数据):
function addMethodMenuItem($result, $short_cat_name, $short_subcat_name, $short_method_name, $this_method_name)
{
$result .= "<li>";
$result .= "<a";
$result .= " href=\"product.php?category={$short_cat_name}&subcategory={$short_subcat_name}&printMethod={$short_method_name}\"";
$result .= " target=\"_self\"";
$result .= " title=\"{$this_method_name}\">";
$result .= $this_method_name;
$result .= "</a>";
$result .= "</li>";
return $result;
}
function addSubMenuItem($item, $previous_cat_name, $previous_subcat_name, $result, $newCat)
{
$this_cat_name = $item["category_name"];
$this_subcat_name = $item["subcategory_name"];
$this_method_name = $item["method_name"];
$short_cat_name = $item["category_short"];
$short_subcat_name = $item["subcategory_short"];
$short_method_name = $item["method_short"];
if ($this_subcat_name != $previous_subcat_name || $this_cat_name != $previous_cat_name) { // We have to create a new "subcategory" menu item
if ($previous_subcat_name != null && !$newCat) { // if this isn't the first subcategory menu item of the category.
$result .= "</ul></li>";
}
$result .= "<li>";
$result .= "<a class=\"ajxsub\"";
$result .= " href=\"#\">";
$result .= $this_subcat_name;
$result .= "</a>";
$result .= "<ul>";
}
$result = addMethodMenuItem($result, $short_cat_name, $short_subcat_name, $short_method_name, $this_method_name);
return $result;
}
function printMenu(array $items, $previous_cat_name, $result)
{
// $result .= "<ul>";
$previous_subcat_name = null;
foreach ($items as $item) {
$newCat = false;
$this_cat_name = $item["category_name"];
$this_subcat_name = $item["subcategory_name"];
if ($this_cat_name != $previous_cat_name) {
if ($previous_cat_name != null) { // if this isn't the very first top-level menu item.
$result .= "</ul></li>";
$result .= "</ul></li>";
$newCat = true;
}
$result .= "<li>";
$result .= "<a class=\"ajxsub\"";
$result .= " href=\"#\">";
$result .= $this_cat_name;
$result .= "</a>";
$result .= "<ul>";
}
$result = addSubMenuItem($item, $previous_cat_name, $previous_subcat_name, $result, $newCat);
$previous_subcat_name = $this_subcat_name;
$previous_cat_name = $this_cat_name;
}
$result .= "</ul></li>";
// $result .= "</ul>";
return $result;
}
试一试 - 假设您已经对数据进行排序(否则先排序):
$flds = ['category_name', 'subcategory_name', 'method_name'];
$lval = ['it will never be this'];
$result = "";
$start = true;
foreach ($items as $item) {
if ($start) {
$result .= "<ul>";
$first = $start = false;
} else $first = true;
foreach ($flds as $k=>$val) {
if ($item[$val] != $lval[$k]) {
$result .= genhtml($k, $item[$val], $first);
$first = false;
$lval[$k] = $item[$val];
$lval[$k+1] = ''; // Don't care if this goes over the max
}
}
}
if (!$start) $result .= "</ul></li></ul></li></ul>\n";
echo $result;
function genhtml($level, $value, $first) {
switch ($level) {
case 0:
$close = $first ? "</ul></li></ul></li>" : "";
return "{$close}<li><a href=\"#\" class=\"level0\">{$value}</a><ul>\n";
case 1:
$close = $first ? "</ul></li>" : "";
return " {$close}<li><a href=\"#\" class=\"level1\">{$value}</a><ul>\n";
case 2:
return " <li><a href=\"#\" class=\"level2\">{$value}</a></li>\n";
default:
throw new Exception("I don't know how to do '{$level}'");
}
}
上面的代码(使用您的一些数据)产生:
<ul><li><a href="#" class="level0">Napkins</a><ul>
<li><a href="#" class="level1">Colored Napkins</a><ul>
<li><a href="#" class="level2">American Tradition</a></li>
</ul></li><li><a href="#" class="level1">White Beverage Napkins</a><ul>
<li><a href="#" class="level2">American Digital</a></li>
<li><a href="#" class="level2">American Tradition</a></li>
<li><a href="#" class="level2">American Hi Speed</a></li>
</ul></li><li><a href="#" class="level1">White Luncheon Napkins</a><ul>
<li><a href="#" class="level2">American Digital</a></li>
<li><a href="#" class="level2">American Tradition</a></li>
<li><a href="#" class="level2">American Hi Speed</a></li>
</ul></li><li><a href="#" class="level1">White Dinner Napkins</a><ul>
<li><a href="#" class="level2">American Digital</a></li>
<li><a href="#" class="level2">American Tradition</a></li>
<li><a href="#" class="level2">American Hi Speed</a></li>
</ul></li></ul></li><li><a href="#" class="level0">Plates</a><ul>
<li><a href="#" class="level1">Eco Plates</a><ul>
<li><a href="#" class="level2">American Tradition</a></li>
</ul></li></ul></li></ul>
(不好看,但我觉得很对)
也将忽略重复的记录(也许不是你想要的?)。如果您需要记录中的其他数据来生成 html,请将 $item 也传递给 genhtml。
对于 PHP,我需要创建一个三层深度的导航栏。我有这样的数据:
我需要这样组织它:
Napkins
--Colored Napkins
----American Tradition
--White Beverage Napkins
----American Digital
----American Tradition
----American Hi-Speed
--White Luncheon Napkins
----American Digital
----American Tradition
----American Hi-Speed
--White Dinner Napkins
...(etc)...
Plates
--Eco-Plates
----American Tradition
--Plastic Trays
...(etc)...
只是使用相对简单的 <ul>
结构,其中包含 <li>
和 <a>
。显然需要一个循环来遍历数据行。而且我知道我需要做很多 "testing" 来查看 "current" category/subcategory/method 是否与上一次循环迭代中的匹配。
但是我无法让 <ul> and <li>
标签在正确的位置关闭并且 不显示 打印方法层只有 one 给定 category/subcategory 的打印方法。或者当有无打印方式时(有时可以是null
,比如塑料器具)。我该如何设置?
编辑
我目前的代码几乎可以工作,但是非常笨拙($items
是数据库中的数据):
function addMethodMenuItem($result, $short_cat_name, $short_subcat_name, $short_method_name, $this_method_name)
{
$result .= "<li>";
$result .= "<a";
$result .= " href=\"product.php?category={$short_cat_name}&subcategory={$short_subcat_name}&printMethod={$short_method_name}\"";
$result .= " target=\"_self\"";
$result .= " title=\"{$this_method_name}\">";
$result .= $this_method_name;
$result .= "</a>";
$result .= "</li>";
return $result;
}
function addSubMenuItem($item, $previous_cat_name, $previous_subcat_name, $result, $newCat)
{
$this_cat_name = $item["category_name"];
$this_subcat_name = $item["subcategory_name"];
$this_method_name = $item["method_name"];
$short_cat_name = $item["category_short"];
$short_subcat_name = $item["subcategory_short"];
$short_method_name = $item["method_short"];
if ($this_subcat_name != $previous_subcat_name || $this_cat_name != $previous_cat_name) { // We have to create a new "subcategory" menu item
if ($previous_subcat_name != null && !$newCat) { // if this isn't the first subcategory menu item of the category.
$result .= "</ul></li>";
}
$result .= "<li>";
$result .= "<a class=\"ajxsub\"";
$result .= " href=\"#\">";
$result .= $this_subcat_name;
$result .= "</a>";
$result .= "<ul>";
}
$result = addMethodMenuItem($result, $short_cat_name, $short_subcat_name, $short_method_name, $this_method_name);
return $result;
}
function printMenu(array $items, $previous_cat_name, $result)
{
// $result .= "<ul>";
$previous_subcat_name = null;
foreach ($items as $item) {
$newCat = false;
$this_cat_name = $item["category_name"];
$this_subcat_name = $item["subcategory_name"];
if ($this_cat_name != $previous_cat_name) {
if ($previous_cat_name != null) { // if this isn't the very first top-level menu item.
$result .= "</ul></li>";
$result .= "</ul></li>";
$newCat = true;
}
$result .= "<li>";
$result .= "<a class=\"ajxsub\"";
$result .= " href=\"#\">";
$result .= $this_cat_name;
$result .= "</a>";
$result .= "<ul>";
}
$result = addSubMenuItem($item, $previous_cat_name, $previous_subcat_name, $result, $newCat);
$previous_subcat_name = $this_subcat_name;
$previous_cat_name = $this_cat_name;
}
$result .= "</ul></li>";
// $result .= "</ul>";
return $result;
}
试一试 - 假设您已经对数据进行排序(否则先排序):
$flds = ['category_name', 'subcategory_name', 'method_name'];
$lval = ['it will never be this'];
$result = "";
$start = true;
foreach ($items as $item) {
if ($start) {
$result .= "<ul>";
$first = $start = false;
} else $first = true;
foreach ($flds as $k=>$val) {
if ($item[$val] != $lval[$k]) {
$result .= genhtml($k, $item[$val], $first);
$first = false;
$lval[$k] = $item[$val];
$lval[$k+1] = ''; // Don't care if this goes over the max
}
}
}
if (!$start) $result .= "</ul></li></ul></li></ul>\n";
echo $result;
function genhtml($level, $value, $first) {
switch ($level) {
case 0:
$close = $first ? "</ul></li></ul></li>" : "";
return "{$close}<li><a href=\"#\" class=\"level0\">{$value}</a><ul>\n";
case 1:
$close = $first ? "</ul></li>" : "";
return " {$close}<li><a href=\"#\" class=\"level1\">{$value}</a><ul>\n";
case 2:
return " <li><a href=\"#\" class=\"level2\">{$value}</a></li>\n";
default:
throw new Exception("I don't know how to do '{$level}'");
}
}
上面的代码(使用您的一些数据)产生:
<ul><li><a href="#" class="level0">Napkins</a><ul>
<li><a href="#" class="level1">Colored Napkins</a><ul>
<li><a href="#" class="level2">American Tradition</a></li>
</ul></li><li><a href="#" class="level1">White Beverage Napkins</a><ul>
<li><a href="#" class="level2">American Digital</a></li>
<li><a href="#" class="level2">American Tradition</a></li>
<li><a href="#" class="level2">American Hi Speed</a></li>
</ul></li><li><a href="#" class="level1">White Luncheon Napkins</a><ul>
<li><a href="#" class="level2">American Digital</a></li>
<li><a href="#" class="level2">American Tradition</a></li>
<li><a href="#" class="level2">American Hi Speed</a></li>
</ul></li><li><a href="#" class="level1">White Dinner Napkins</a><ul>
<li><a href="#" class="level2">American Digital</a></li>
<li><a href="#" class="level2">American Tradition</a></li>
<li><a href="#" class="level2">American Hi Speed</a></li>
</ul></li></ul></li><li><a href="#" class="level0">Plates</a><ul>
<li><a href="#" class="level1">Eco Plates</a><ul>
<li><a href="#" class="level2">American Tradition</a></li>
</ul></li></ul></li></ul>
(不好看,但我觉得很对)
也将忽略重复的记录(也许不是你想要的?)。如果您需要记录中的其他数据来生成 html,请将 $item 也传递给 genhtml。