如何递归构建具有未知树深度的<select> </select>

时间:2012-04-04 12:34:28

标签: php recursion tree

我有一个带有树数据结构的MySQL表。字段为_idnameparentId。当记录没有父级时,parentId默认为0.这样我就可以构建一个数组,然后递归打印每条记录。

构建的数组如下所示:

Array
(
    [1] => Array
        (
            [parentId] => 0
            [name] => Countries
            [_id] => 1
            [children] => Array
                (
                    [2] => Array
                        (
                            [parentId] => 1
                            [name] => America
                            [_id] => 2
                            [children] => Array
                                (
                                    [3] => Array
                                        (
                                            [parentId] => 2
                                            [name] => Canada
                                            [_id] => 3
                                            [children] => Array
                                                (
                                                    [4] => Array
                                                        (
                                                            [parentId] => 3
                                                            [name] => Ottawa
                                                            [_id] => 4
                                                        )

                                                )

                                        )

                                )

                        )

                    [5] => Array
                        (
                            [parentId] => 1
                            [name] => Asia
                            [_id] => 5
                        )

                    [6] => Array
                        (
                            [parentId] => 1
                            [name] => Europe
                            [_id] => 6
                            [children] => Array
                                (
                                    [7] => Array
                                        (
                                            [parentId] => 6
                                            [name] => Italy
                                            [_id] => 7
                                        )

                                    [11] => Array
                                        (
                                            [parentId] => 6
                                            [name] => Germany
                                            [_id] => 11
                                        )

                                    [12] => Array
                                        (
                                            [parentId] => 6
                                            [name] => France
                                            [_id] => 12
                                        )

                                )

                        )

                    [8] => Array
                        (
                            [parentId] => 1
                            [name] => Oceania
                            [_id] => 8
                        )

                )

         )

 )

使用递归打印无序列表<ul>非常简单。这是我使用的功能:

function toUL ($arr) {

    $html = '<ul>' . PHP_EOL;

    foreach ( $arr as $v ) {

        $html.= '<li>' . $v['name'] . '</li>' . PHP_EOL;

        if ( array_key_exists('children', $v) ) {
            $html.= toUL($v['children']);
        }

    }

    $html.= '</ul>' . PHP_EOL;

    return $html;
}

但是我坚持以树形结构方式打印<select>

Countries
-- America
---- Canada
------ Ottawa
-- Asia
-- Europe
---- Italy
---- Germany
---- France
-- Oceania

我想打印--的次数与元素的深度一样多,但我不知道如何计算深度。

我的问题是:是否可以在不知道深度的情况下构建<select>

提前谢谢。

8 个答案:

答案 0 :(得分:6)

传递一个参数来计算迭代次数$pass

function toUL ($arr, $pass = 0) {

    $html = '<ul>' . PHP_EOL;

    foreach ( $arr as $v ) {           

        $html.= '<li>';
        $html .= str_repeat("--", $pass); // use the $pass value to create the --
        $html .= $v['name'] . '</li>' . PHP_EOL;

        if ( array_key_exists('children', $v) ) {
            $html.= toUL($v['children'], $pass+1);
        }

    }

    $html.= '</ul>' . PHP_EOL;

    return $html;
}

答案 1 :(得分:3)

您的问题已在SPL中解决。 RecursiveIteratorIteratorDocs包含有关某个项目深度的信息:

$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($array), SELF_FIRST);
foreach ($it as $key => $element)
{
    if ($key !== 'name') continue;
    $inset = str_repeat('--', $it->getDepth());
    printf('<option>%s %s</option>', $inset, $element);
}

答案 2 :(得分:1)

function toSelect($arr, $depth = 0) {

    $html = '';

    foreach ( $arr as $v ) {           

        $html.= '<option>' . str_repeat("--", $depth) . $v['name'] . '</option>' . PHP_EOL;

        if ( array_key_exists('children', $v) ) {
            $html.= toSelect($v['children'], $depth++);
        }

    }


    return $html;
}

答案 3 :(得分:1)

我的最终解决方案(感谢Starx和varan):

function toSelect ($arr, $depth=0) {    
    $html = '';
    foreach ( $arr as $v ) {

        $html.= '<option value="' . $v['_id'] . '">';
        $html.= str_repeat('--', $depth);
        $html.= $v['name'] . '</option>' . PHP_EOL;

        if ( array_key_exists('children', $v) ) {
            $html.= toSelect($v['children'], $depth+1);
        }
    }

    return $html;
}

echo '<select>';
echo toSelect($array);
echo '</select>';

即使RecursiveIteratorIterator解决方案也很好(感谢hakre)。

答案 4 :(得分:1)

嗨,大家好,你可以这样做: 我有$tree的这个对象:

   Array
(
    [0] => stdClass Object
        (
            [id] => 1
            [nombre] => Category 1
            [subcategorias] => Array
                (
                    [0] => stdClass Object
                        (
                            [id] => 4
                            [nombre] => Category 1.1
                        )

                )

        )

    [1] => stdClass Object
        (
            [id] => 2
            [nombre] => Category 2
        )

    [2] => stdClass Object
        (
            [id] => 3
            [nombre] => Category 3
            [subcategorias] => Array
                (
                    [0] => stdClass Object
                        (
                            [id] => 5
                            [nombre] => Category 3.1
                            [subcategorias] => Array
                                (
                                    [0] => stdClass Object
                                        (
                                            [id] => 6
                                            [nombre] => Category 3.1.1
                                        )

                                )

                        )

                )

        )

)

然后是如何为HTML选择创建数组:

    $tree=array();// PUT HERE YOUR TREE ARRAY
    $arrayiter = new RecursiveArrayIterator($tree);
    $iteriter = new RecursiveIteratorIterator($arrayiter);
    $lista=array();
    $i=0;
    foreach ($iteriter as $key => $value) 
    {
        $id=$iteriter->current();
        $iteriter->next();
        $nivel=$iteriter->getDepth();
        $nombre=str_repeat('-',$nivel-1).$iteriter->current();
        $lista[$id]=$nombre;
    }

你会得到这样的东西:

    Array
(
    [1] => Category 1
    [4] => --Category 1.1
    [2] => Category 2
    [3] => Category 3
    [5] => --Category 3.1
    [6] => ----Category 3.1.1
)

然后你只需要用一个简单的foreach为select创建选项。

答案 5 :(得分:0)

您可以将长度传递给函数并在递归调用时递增它,然后使用变量$length来确定深度

function toUL ($arr, $length = 0) {

    $html = '<ul>' . PHP_EOL;

    foreach ( $arr as $v ) {

        $html.= '<li>' . $v['name'] . '</li>' . PHP_EOL;

        if ( array_key_exists('children', $v) ) {
            $html.= toUL($v['children'], $length++);
        }

    }

    $html.= '</ul>' . PHP_EOL;

    return $html;
}

这就是我通常用来跟踪递归深度,通常可以完成工作

答案 6 :(得分:0)

function toUL ($arr, $depth = 0) {
//    ...
$html .= toUL($v['children'], $depth+1);

答案 7 :(得分:0)

您可以使用optgroup作为迭代器。 例如:

<select name="list">
  <option value=1>1st option</option>
  <optgroup>
    <option value=10>1st on 1st group</option>
  </optgroup>
</select>

如果你想要php,你可以试试这个:

<?PHP
function toSELECT($arr,$depth=0)
{
$html="";
if(is_array($arr))
    {
    $html.=($depth==0)?"<select name='html'>\n":"";
    foreach ($arr as $key=>$value)
        {
        if(is_array($arr[$key]))
            {
            $html.=str_repeat("\t",$depth)."<optgroup>\n";
            $html.=str_repeat("\t",$depth).toHTML($arr[$key],$depth+1);
            $html.=str_repeat("\t",$depth)."</optgroup>\n";
            }
        else
            {
            $html.=str_repeat("\t",$depth)."<option value='".$value."'>".$key."</option>\n";
            }
        }
    $html.=($depth==0)?"</select>\n":"";
    }
return $html;
}

?>