我有一个有点复杂的递归postgresql查询,它引入了一些东西(我已经为了这个问题的目的简化了它),如下所示:
id depth path has_children
1 1 1 true
2 2 1.2 true
3 3 1.2.3 true
4 4 1.2.3.4 true
5 5 1.2.3.4.5 false
6 1 6 true
7 2 6.7 true
8 3 6.7.8 false
9 1 9 false
10 1 10 true
11 2 10.11 false
这是获取的结果(对于那些想知道为什么我将一些数组解析为对象的人,因为行被提取为对象而我只是复制了结果):
$tree = array
(
(object) array
(
"id" => 1,
"depth" => 1,
"path" => "1",
"has_children" => true
),
(object) array
(
"id" => 2,
"depth" => 2,
"path" => "1.2",
"has_children" => true
),
(object) array
(
"id" => 3,
"depth" => 3,
"path" => "1.2.3",
"has_children" => true
),
(object) array
(
"id" => 4,
"depth" => 4,
"path" => "1.2.3.4",
"has_children" => true
),
(object) array
(
"id" => 5,
"depth" => 5,
"path" => "1.2.3.4.5",
"has_children" => false
),
(object) array
(
"id" => 6,
"depth" => 1,
"path" => "6",
"has_children" => true
),
(object) array
(
"id" => 7,
"depth" => 2,
"path" => "6.7",
"has_children" => true
),
(object) array
(
"id" => 8,
"depth" => 3,
"path" => "6.7.8",
"has_children" => false
),
(object) array
(
"id" => 9,
"depth" => 1,
"path" => "9",
"has_children" => false
),
(object) array
(
"id" => 10,
"depth" => 1,
"path" => "10",
"has_children" => true
),
(object) array
(
"id" => 11,
"depth" => 2,
"path" => "10.11",
"has_children" => false
)
);
我想将结果转换为此(使用给定的类名称):
<div id="foo">
<div class="bar">
<div class="qux">
<p>1</p>
</div>
<div class="baz">
<div class="qux">
<p>1.2</p>
</div>
<div class="baz">
<div class="qux">
<p>1.2.3</p>
</div>
<div class="baz">
<div class="qux">
<p>1.2.3.4</p>
</div>
<div class="baz">
<div class="qux">
<p>1.2.3.4.5</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="bar">
<div class="qux">
<p>6</p>
</div>
<div class="baz">
<div class="qux">
<p>6.7</p>
</div>
<div class="baz">
<div class="qux">
<p>6.7.8</p>
</div>
</div>
</div>
</div>
<div class="bar">
<div class="qux">
<p>9</p>
</div>
</div>
<div class="bar">
<div class="qux">
<p>10</p>
</div>
<div class="baz">
<div class="qux">
<p>10.11</p>
</div>
</div>
</div>
</div>
然而,在查看涉及ul
和li
的太多示例后,我已经迷茫了自己。由于嵌套的ul
和li
与嵌套的div
不同,因此为我的使用调整此类示例失败。
我想要一个使用foreach
(最好)或while
循环的干净解决方案(不需要递归函数)。我也不希望将结果重新创建为多维数组。
答案 0 :(得分:1)
您需要将db数据提取到一个数组中,您可以循环并使用depth和has_children,将数据传递给新的多维数组:
array(
'1' => array(
'1.2' => array(
'1.2.3' => array(
'1.2.3.4' => array('1.2.3.4.5')
)
)
),
'6' => array(
'6.7' => array('6.7.8')
)
);
等。然后你可以循环它并使用foreach将每个数组作为div回显。
想象一下,您使用array('row' => array('key' => 'value', 'etc' => 'more'))
形式发布的示例表中的已获取数据。对于每一行,您需要检查['has_children']
值。如果它的计算结果为true,那么你应该将深度作为一个整数并使用for循环,例如for ($i=0; $i<$depth; $i++)
,创建一个数组数组,如上所示。
有几种方法可以做到这一点,更简单的方法是递归地创建数组,例如
$array = '1.2.3.4.5'
然后$array = array('1.2.3.4' => $array)
,直到你有一个如上所述的多维数组。
拥有该数组,就像:
一样简单function display($multiarray) {
foreach ($multiarray as $name=>$path) {
if (is_array($path)) {
// Check if it's the first.
$class = (strpos('.', $name)) ? 'baz' : 'bar';
echo "<div class='{$class}'>\n\t";
echo "<div class='qux'>\n\t<p>{$name}</p>\n</div>\n\n";
display($path);
echo "</div>";
} else {
echo "<div class='baz'>\n\t";
echo "<div class='qux'>\n\t<p>{$path}</p>\n</div>";
echo "</div>";
}
}
}
动态制作,但我希望你能得到主要的想法。
答案 1 :(得分:1)
您的数据持平会使编写递归函数变得更加困难。递归函数最自然地与嵌套数据一起工作。花了一段时间,但我能够创建一个与您的平面数据一起使用的部分递归解决方案。
<?php
$tree = array(array("id"=>1,"depth"=>1,"path"=>"1","has_children"=>true),array("id"=>2,"depth"=>2,"path"=>"1.2","has_children"=>true),array("id"=>3,"depth"=>3,"path"=>"1.2.3","has_children"=>true),array("id"=>4,"depth"=>4,"path"=>"1.2.3.4","has_children"=>true),array("id"=>5,"depth"=>5,"path"=>"1.2.3.4.5","has_children"=>false),array("id"=>6,"depth"=>1,"path"=>"6","has_children"=>true),array("id"=>7,"depth"=>2,"path"=>"6.7","has_children"=>true),array("id"=>8,"depth"=>3,"path"=>"6.7.8","has_children"=>false),array("id"=>9,"depth"=>1,"path"=>"9","has_children"=>false),array("id"=>10,"depth"=>1,"path"=>"10","has_children"=>true),array("id"=>11,"depth"=>2,"path"=>"10.11","has_children"=>false));
header('Content-Type: text/plain');
function print_tree(&$tree, $i, $top_level)
{
$indent = str_repeat(' ', $tree[$i]['depth']);
echo $indent."<div class=\"".($top_level ? 'bar' : 'baz')."\">\n";
echo $indent." <div class=\"qux\">\n";
echo $indent." <p>".$tree[$i]['path']."</p>\n";
echo $indent." </div>\n";
if($tree[$i]['has_children'])
{
print_tree($tree, $i+1, false);
}
echo $indent."</div>\n";
}
echo "<div id=\"foo\">\n";
$count = count($tree);
for($i = 0; $i < $count; ++$i)
{
if($tree[$i]['depth'] == 1)
{
print_tree($tree, $i, true);
}
}
echo "</div>\n";
?>
这将输出:
<div id="foo">
<div class="bar">
<div class="qux">
<p>1</p>
</div>
<div class="baz">
<div class="qux">
<p>1.2</p>
</div>
<div class="baz">
<div class="qux">
<p>1.2.3</p>
</div>
<div class="baz">
<div class="qux">
<p>1.2.3.4</p>
</div>
<div class="baz">
<div class="qux">
<p>1.2.3.4.5</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="bar">
<div class="qux">
<p>6</p>
</div>
<div class="baz">
<div class="qux">
<p>6.7</p>
</div>
<div class="baz">
<div class="qux">
<p>6.7.8</p>
</div>
</div>
</div>
</div>
<div class="bar">
<div class="qux">
<p>9</p>
</div>
</div>
<div class="bar">
<div class="qux">
<p>10</p>
</div>
<div class="baz">
<div class="qux">
<p>10.11</p>
</div>
</div>
</div>
</div>
答案 2 :(得分:1)
这个闪亮的纯SQL 将完全生成您的字符串:
WITH x AS (
SELECT *
,(lag(depth) OVER (ORDER BY id) +1) - depth AS end_divs
,CASE WHEN depth = 1 THEN 'bar' ELSE 'baz' END AS class
,E'\n' || repeat(' ', depth) AS i -- newline + indent
FROM tbl
ORDER BY id
)
SELECT '<div id="foo">'
|| string_agg(
CASE WHEN end_divs > 0 THEN
(SELECT string_agg(repeat (' ', n), E'</div>\n')
FROM generate_series (end_divs,0,-1) n)
ELSE '' END
|| i || '<div class="' || class ||'">'
|| i || ' <div class="qux">'
|| i || ' <p>' || path || '</p>'
|| i || ' </div>'
, E'\n' ORDER BY id
)
|| (SELECT E'\n' || string_agg(repeat (' ', n-1), E'</div>\n')
FROM generate_series((SELECT depth+1 FROM tbl ORDER BY id DESC LIMIT 1)
, 0 , -1) n)
FROM x;
阅读起来并不容易,我会留下将这些功能记录下来。
答案 3 :(得分:1)
可能不是最漂亮的代码,但它完全按照您的指定输出:
<div id="foo">
<?php
$openingElement = true;
$divsOpened = 0;
$indent = 1;
foreach ($tree as $row) {
if ($openingElement === true) {
print str_repeat(' ', $indent * 4) . '<div class="bar">' . PHP_EOL;
} else {
print str_repeat(' ', $indent * 4) . '<div class="baz">' . PHP_EOL;
}
$indent++;
$divsOpened++;
print str_repeat(' ', $indent * 4) . '<div class="qux">' . PHP_EOL;
$indent++;
print str_repeat(' ', $indent * 4) . '<p>' . $row->path . '</p>' . PHP_EOL;
$indent--;
print str_repeat(' ', $indent * 4) . '</div>' . PHP_EOL;
if ($row->has_children) {
$openingElement = false;
print PHP_EOL;
} else {
for ($i = $divsOpened; $i > 0; $i--) {
print str_repeat(' ', $i * 4) . '</div>' . PHP_EOL;
$indent--;
$divsOpened--;
}
$openingElement = true;
}
}
?>
</div>