【问题标题】:Php: Converting a flat array into a tree like structure [closed]Php:将平面数组转换为树状结构[关闭]
【发布时间】:2013-03-03 18:13:58
【问题描述】:

我需要有关数组转换的帮助。我有一个看起来像这样的平面数组:

Array
(
[0] =>  av_one_third
[1] =>  av_icon_box
[2] =>  /av_icon_box
[3] =>  av_button
[4] =>  av_icon_box
[5] =>  /av_icon_box
[6] =>  /av_one_third

)

这个数组的值实际上是来自类似 xml 的结构的标签。我现在需要的是将此数组转换为类似于以下结构的嵌套数组:

[0] => Array
    (
        [tag] => av_one_third
        [content] => Array
            (
                [1] => Array
                    (
                        [tag] => av_icon_box
                        [content] => Array
                            (
                            )

                    )

                [2] => Array
                    (
                        [tag] => av_button
                        [content] => Array
                            (
                            )

                    )  

                [3] => Array
                    (
                        [tag] => av_icon_box
                        [content] => Array
                            (
                            )

                    )


            )

    )
etc

有没有简单的方法来做到这一点?我的第一个想法是将数组转换为 xml 字符串并使用 phps 本机 XML 函数之一,但问题是自闭标签没有这样标记。在上面的例子中,av_button 标签没有结束标签抛出了我尝试的 xml 解析函数。

一些额外的要求: - 元素可以容纳任意数量的孩子 - 最终数组必须保持正确的顺序

是否有任何智能数组排序功能可以轻松解决这个问题? 将不胜感激任何提示!

最好的问候:)

【问题讨论】:

  • 您确定使用XML Parser 不是更好吗?否则你需要创建一个递归函数。

标签: php xml arrays sorting


【解决方案1】:

您的数组有一个典型的平面结构编码一个层次结构。但前提是你修复了那里的错误。

它基本上可以像下面的 PHP 代码列表那样工作,包括告诉数据中错误在哪里的异常,以便您可以修复数据(您可以在此网站上找到类似的示例,例如查看 How can I convert a series of parent-child relationships into a hierarchical tree? 中的链接问题):

  1. 初始化树数组中的根条目。在那里你可以添加孩子。

    $tree     = ['children' => []];
    
  2. 创建一个指向树的指针数组,它的第一个元素(级别 0)指向树的根元素:

    $pointers = [&$tree];
    
  3. 现在遍历数据中的每一行:

    foreach ($data as $index => $line) {
    
  4. 决定线路是否关闭并存储该决定结果:

    $close = '/' === $line[0];
    
  5. 存储当前的指针计数:

    $count = count($pointers);
    
  6. 如果行没有关闭,打开一个新元素并继续:

    $pointers[$count]                   = ['tag' => $line, 'children' => []];
    $pointers[$count - 1]['children'][] = & $pointers[$count];
    continue;
    
  7. 如果该行确实关闭,则验证标记名是否匹配,如果匹配,则删除最后创建的指针:

    if ($count === 1) {
        throw new RuntimeException('Can not close on lowest level.');
    }
    
    $name = $pointers[$count - 1]['tag'];
    
    if ($name !== substr($line, 1)) {
        throw new RuntimeException(
            "Invalid closing element <$line> (line #$index) in <$name>"
        );
    }
    
    array_pop($pointers);
    
  8. 在所有行都被处理后,所有指针都可以被删除:

    unset($pointers);
    
  9. 结果是可以在根节点的第一个子节点中找到的数组。它可以分配给一个变量,然后可以删除不需要的引用:

    $result = &$tree['children'][0];
    unset($tree);
    print_r($result);
    

如果数据正确,则示范输出:

Array
(
    [tag] => av_one_third
    [children] => Array
        (
            [0] => Array
                (
                    [tag] => av_icon_box
                    [children] => Array
                        (
                        )
                )
            [1] => Array
                (
                    [tag] => av_button
                    [children] => Array
                        (
                        )
                )
            [2] => Array
                (
                    [tag] => av_icon_box
                    [children] => Array
                        (
                        )
                )
        )
)

【讨论】:

  • 谢谢!不知道为什么这实际上已关闭,但这正是我想要的:)
  • 它可能已关闭,因为目前尚不清楚您做了什么。更好地展示您尝试过的内容以及遇到障碍的地方,这样问题就更清楚了。顺便说一句:XML 解决方案更简单,但它没有给你数组。
  • 谢谢!实际上我已经取消了 xml 解决方案,但是由于带有标签的初始数组是由用户输入生成的,所以我喜欢这样的想法,即当标签嵌套不正确而不是异常时,我至少有一些东西可以使用:) 无论如何,再次感谢; )
  • 您也可以在每个标签中留下行号($data 中的索引),以便您可以回顾并在错误消息中告诉标签打开的位置与关闭标签匹配。这可能会帮助您更详细地处理错误条件。
猜你喜欢
  • 2015-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-03
  • 1970-01-01
  • 1970-01-01
  • 2023-01-13
  • 1970-01-01
相关资源
最近更新 更多