[英]Create a multi-dimensional array with PHP from lineal array
TL;DR我正在寻找一个函数来从 PHP 中的一维数组创建嵌套的<ol>
列表。
1)目前我的测试页面中有这个简化的标记:
<h2>Spiders</h2>
<h2>Beetles</h2>
<h3>External morphology</h3>
<h4>Head</h4>
<h4>Thorax</h4>
<h4>Legs</h4>
<h3>Anatomy and physiology</h3>
<h2>Ants</h2>
2)然后被一个非常简单的函数捕获到一个一维数组中,如下所示:
array
(
0 => "H2 Spiders",
1 => "H2 Beetles",
2 => "H3 External morphology",
3 => "H4 Head",
4 => "H4 Thorax",
5 => "H4 Legs",
6 => "H3 Anatomy and physiology"
7 => "H2 Ants"
);
3)这是棘手的部分,因为我使用下一个循环和这些过于复杂的 if 语句来填充多维数组。
$toc = array ();
//
foreach ($array as $value) {
$value_arr = explode(' ', $value, 2);
$depth = str_replace("H", "", $value_arr[0]);
$content = $value_arr[1];
//
if ($depth == 1) $toc[$title] = null;
elseif ($depth == 2) {
if (empty (end ($toc))) $toc[array_key_last ($toc)] = array ($title => null);
else $toc[array_key_last ($toc)][$title] = null;
} elseif ($depth == 3) {
if (empty (end ($toc[array_key_last ($toc)]))) $toc[array_key_last ($toc)][array_key_last ($toc[array_key_last ($toc)])] = array ($title => null);
else $toc[array_key_last ($toc)][array_key_last ($toc[array_key_last ($toc)])][$title] = '';
}
}
输出:
Array (
[Spiders] =>
[Beetles] => Array
(
[External morphology] => Array
(
[Head] =>
[Thorax] =>
[Legs] =>
)
[Anatomy and physiology] =>
)
[Ants] =>
)
4)最后用这个函数解析成一个完美缩进的html列表。
function table_of_contents ($toc, $output = '') {
foreach ($toc as $key => $value) {
$output = "$output <li><a href='#@" . sanitize_title ($key) . "'>$key</a>" . (is_array ($value) ? table_of_contents ($value) : null) . '</li>';
}
//
return "<ol>$output</ol>";
}
//
table_of_contents ($toc);
——
在第 1、第 2 和第 4 步中一切正常,但我目前的方法有一个缺点,即在第 3 步中仅允许我从第一个数组获得最多三个级别的深度。
我的问题是是否有一种更有效、更简洁的方法来创建具有(也许)递归函数或类似函数的多维数组?
使用preg_match_all
解析输入可能更容易; 这可以为您提供深度和相关值的数组。 然后你可以遍历这些数组,当深度增加时打开一个<ol>
,当深度减少时关闭它:
$html = '<h2>Spiders</h2>
<h2>Beetles</h2>
<h3>External morphology</h3>
<h4>Head</h4>
<h4>Thorax</h4>
<h4>Legs</h4>
<h3>Anatomy and physiology</h3>
<h2>Ants</h2>';
preg_match_all('/<h(\d)>([^<]+)/', $html, $matches);
$cdepth = $matches[1][0] - 1;
foreach ($matches[1] as $key => $depth) {
if ($depth > $cdepth) {
echo "\n" . str_repeat(' ', $cdepth * 4) . "<ol>\n";
}
elseif ($depth < $cdepth) {
echo "</li>\n" . str_repeat(' ', $depth * 4) . "</ol>\n" . str_repeat(' ', $depth * 4) . "</li>\n";
}
else {
echo "</li>\n";
}
$cdepth = $depth;
echo str_repeat(' ', $cdepth * 4) . "<li><a href=\"{$matches[2][$key]}\">{$matches[2][$key]}</a>";
}
while ($cdepth-- >= $matches[1][0]) {
echo "</li>\n" . str_repeat(' ', $cdepth * 4) . "</ol>\n";
}
输出:
<ol> <li><a href="Spiders">Spiders</a></li> <li><a href="Beetles">Beetles</a> <ol> <li><a href="External morphology">External morphology</a> <ol> <li><a href="Head">Head</a></li> <li><a href="Thorax">Thorax</a></li> <li><a href="Legs">Legs</a></li> </ol> </li> <li><a href="Anatomy and physiology">Anatomy and physiology</a></li> </ol> </li> <li><a href="Ants">Ants</a></li> </ol>
更新
如果出于输出以外的其他原因想要第三阶段数组,则可以使用此递归函数生成它(仍然可以从preg_match_all
的输出中使用):
$html = '<h2>Spiders</h2>
<h2>Beetles</h2>
<h3>External morphology</h3>
<h4>Head</h4>
<h4>Thorax</h4>
<h4>Legs</h4>
<h5>Feet</h5>
<h3>Anatomy and physiology</h3>
<h2>Ants</h2>';
function push_values(&$k, $depth, $content) {
$output = array();
$cdepth = $depth[$k];
while ($k < count($depth)) {
if ($depth[$k] == $cdepth) {
$output[$content[$k]] = '';
$k++;
}
elseif ($depth[$k] > $cdepth) {
$output[$content[$k-1]] = push_values($k, $depth, $content);
}
else {
return $output;
}
}
return $output;
}
preg_match_all('/<h(\d)>([^<]+)/', $html, $matches);
$key = 0;
print_r(push_values($key, $matches[1], $matches[2]));
输出:
Array
(
[Spiders] =>
[Beetles] => Array
(
[External morphology] => Array
(
[Head] =>
[Thorax] =>
[Legs] => Array
(
[Feet] =>
)
)
[Anatomy and physiology] =>
)
[Ants] =>
)
最后,我建议对@Nick 发布的第一个代码进行小修,在下一个场景中导致不受欢迎的 HTML 输出,其中大于 2 的深度差异将改变最肤浅的兄弟姐妹; 例如, <h6>
<h3>
之后的<h3>
变成了<h5>
而下一个<h2>
被解析为<h4>
:
$html = '<h2>Spiders</h2>
<h2>Beetles</h2>
<h3>External morphology</h3>
<h4>Head</h4>
<h4>Thorax</h4>
<h4>Legs</h4>
<h5>Feet</h5>
<h6>Toes</h6>
<h3>Anatomy and physiology</h3>
<h2>Ants</h2>';
foreach ($matches[1] as $key => $depth) {
if ($depth > $cdepth) {
echo "\n" . str_repeat(' ', $cdepth * 4) . "<ol>\n";
}
elseif ($depth < $cdepth) {
echo "</li>\n" . str_repeat(' ', $depth * 4) . "</ol>\n" . str_repeat(' ', $depth * 4) . "</li>\n";
}
else {
echo "</li>\n";
}
$cdepth = $depth;
echo str_repeat(' ', $cdepth * 4) . "<li><a href=\"{$matches[2][$key]}\">{$matches[2][$key]}</a>";
}
while ($cdepth-- >= $matches[1][0]) {
echo "</li>\n" . str_repeat(' ', $cdepth * 4) . "</ol>\n";
}
输出:
<ol> <li><a href="Spiders">Spiders</a></li> <li><a href="Beetles">Beetles</a> <ol> <li><a href="External morphology">External morphology</a> <ol> <li><a href="Head">Head</a></li> <li><a href="Thorax">Thorax</a></li> <li><a href="Legs">Legs</a> <ol> <li><a href="Feet">Feet</a> <ol> <li><a href="Toes">Toes</a></li> </ol> </li> <li><a href="Anatomy and physiology">Anatomy and physiology</a></li> </ol> </li> <li><a href="Ants">Ants</a></li> </ol> </li></ol></li></ol>
——
为了解决这个问题,我在添加下一个<li>
元素之前添加了另一个while语句来放置正确数量的</li></ol>
,现在可以正确验证 W3C 检查器。
foreach ($matches[1] as $key => $depth) {
if ($depth > $cdepth) {
echo "\n" . str_repeat(' ', $cdepth * 4) . "<ol>\n";
}
elseif ($depth < $cdepth) {
while ($cdepth -- > $depth) {
echo "</li>\n" . str_repeat(' ', $depth * 4) . "</ol>\n" . str_repeat(' ', $depth * 4) . "\n";
}
}
else {
echo "</li>\n";
}
$cdepth = $depth;
echo str_repeat(' ', $cdepth * 4) . "<li><a href=\"{$matches[2][$key]}\">{$matches[2][$key]}</a>";
}
while ($cdepth-- >= $matches[1][0]) {
echo "</li>\n" . str_repeat(' ', $cdepth * 4) . "</ol>\n";
}
输出:
<ol> <li><a href="Spiders">Spiders</a></li> <li><a href="Beetles">Beetles</a> <ol> <li><a href="External morphology">External morphology</a> <ol> <li><a href="Head">Head</a></li> <li><a href="Thorax">Thorax</a></li> <li><a href="Legs">Legs</a> <ol> <li><a href="Feet">Feet</a> <ol> <li><a href="Toes">Toes</a></li> </ol> </li> </ol> </li> </ol> <li><a href="Anatomy and physiology">Anatomy and physiology</a></li> </ol> <li><a href="Ants">Ants</a></li> </ol>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.