使用递归PHP函数解析JSON字符串,如何将数据从一项传递到下一项?


Using a recursive PHP function to parse a JSON string, how can I pass data from one item to the next?

更具体地说,我希望将父ID传递给孩子,更重要的是,如果孩子有孙子,我需要将孩子的ID传递给孙子…以此类推,无限数量的嵌套项(因此使用递归函数)。

注意:这篇文章看起来很长,但它主要只是输出数据!我很确定有一个简单的解决办法,但是经过几个小时的尝试,我还是想不出来。

到目前为止,我有这个:

<?php
session_start();
$data = '[{"id":13,"content":"This is some content"},{"id":14,"content":"This is some content"},{"id":15,"content":"This is some content","children":[{"id":16,"content":"This is some content"},{"id":17,"content":"This is some content"},{"id":18,"content":"This is some content","children":[{"id":19,"content":"This is some content","children":[{"id":20,"content":"This is some content","children":[{"id":21,"content":"This is some content"},{"id":22,"content":"This is some content"},{"id":23,"content":"This is some content"}]}]}]}]},{"id":24,"content":"This is some content"},{"id":25,"content":"This is some content"}]';
$menu = json_decode($data, true); 
$depth = 0;

function getData($array, $key, $depth) {
    if (!is_array($array)) {
        $depth = $depth/2;
        $depthHolder = $depth;
        if ($key == "id") {
            //I thought maybe I could write something in here to this effect, but was unsuccessful :(   
        }
        while ($depth != 1) {
            echo "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";            
            $depth--;
        }

        echo $depthHolder . ' - ' . $key . ' : ' . $array . '<br/> ';
    } else {
        $depth++;   
    }

    foreach($array as $key => $v) { 
        getData($v, $key, $depth);
    }

}
getData($menu, '', $depth);
?>

输出这个(目前前面的数字只是显示嵌套项的深度):

1 - id : 13
1 - content : This is some content
1 - id : 14
1 - content : This is some content
1 - id : 15
1 - content : This is some content
        2 - id : 16
        2 - content : This is some content
        2 - id : 17
        2 - content : This is some content
        2 - id : 18
        2 - content : This is some content
                3 - id : 19
                3 - content : This is some content
                        4 - id : 20
                        4 - content : This is some content
                                5 - id : 21
                                5 - content : This is some content
                                5 - id : 22
                                5 - content : This is some content
                                5 - id : 23
                                5 - content : This is some content
1 - id : 24
1 - content : This is some content
1 - id : 25
1 - content : This is some content

我尝试使用会话,但我仍然无法弄清楚。下面的示例输出显示了我正在寻找的内容。您将注意到,行前面的ID已经更改为显示先前的父ID,并保持它,直到下一个嵌套项显示(0表示'无父')。

0 - id : 13
0 - content : This is some content
0  - id : 14
0 - content : This is some content
0 - id : 15
0 - content : This is some content
        15 - id : 16
        15 - content : This is some content
        15 - id : 17
        15 - content : This is some content
        15 - id : 18
        15 - content : This is some content
                18 - id : 19
                18 - content : This is some content
                        19 - id : 20
                        19 - content : This is some content
                                20 - id : 21
                                20 - content : This is some content
                                20 - id : 22
                                20 - content : This is some content
                                20 - id : 23
                                20 - content : This is some content
0 - id : 24
0 - content : This is some content
0 - id : 25
0 - content : This is some content

很抱歉写了这么长时间!谢谢你的阅读,希望你们中的一个天才能帮助我。我很感激,因为我花了6个小时来解决这个小问题。

也许这种方法会更清楚:

function getData($parentkey,$array,$depth) {
  foreach ($array as $v) {
    print "$depth $parentkey id: {$v['id']}<br>$depth $parentkey content:{$v['content']}<br>";
    if (isset($v['children']))
      getData($v['id'],$v['children'],$depth."&nbsp;&nbsp;");
  }
}
getData(0,$menu,'');

如果尝试以这种方式构建菜单,则需要修改返回的数据结构。例如…

class item {
    public $id;
    public $content;
    public $subsections;
}

然后您可以通过检查解析函数中它们是否有任何子节,简单地将它们创建为嵌套的无序列表。

function parse_items($items) {
    $html = '<ul>';
    foreach ($items as &$item) {
        $html .= '<li>' . $item->content . '</li>';
        if (count($item->subsections) > 0) {
            $html .= parse_items($item->subsections);
        }
    }
    $html .= '</ul>'
    return $html;
}
echo parse_items($items);

之后,您可以根据<ul>元素的深度使用CSS来设置菜单的显示样式。从技术上讲,我知道这是"作弊",因为我在整个数据结构的旁边添加了一个元素数组,但如果您可以控制元素的返回方式,为什么不让自己更轻松呢?

您可以使用以下代码添加父ID:

function getData($arr, $parent=null) {
    if (is_array($arr)) {
        if (!isset($arr['id'])) {
            foreach ($arr as $key => $item) {
                $arr[$key] = getData($item, $parent);
            }
        } else {
            $id = $arr['id'];
            if ($parent) {
                $arr['parent'] = $parent;
            }
            if (isset($arr['children'])) {
                $arr['children'] = getData($arr['children'], $id);
            }
        }
    }
    return $arr;
}

print_r(getData($menu)); 

一种方法:

function print_menu($menu, $key, $depth) {
    $indent_string = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
    foreach ($menu as $value) {
        $this_key = $value['id'];
        echo str_repeat ($indent_string, $depth).$key." - id : ".$value['id']."</br>";
        echo str_repeat ($indent_string, $depth).$key." - content : ".$value['content']."</br>";
        if (is_array($value['children'])) {
            print_menu ($value['children'],$this_key,$depth+1);
        }
    }
}
print_menu ($menu, 0, 0);

如果你想为菜单生成HTML,你可以使用:

function print_menu_1 ($menu, $key, $depth) {
    $indent_string = "    ";
    echo str_repeat($indent_string,$depth).'<ol class="dd-list">'."'n";
    foreach ($menu as $value) {
        $this_key = $value['id'];
        echo str_repeat($indent_string,$depth+1).'<li class="dd-item" data-id="'.$value['id'].'">'."'n";
        echo str_repeat($indent_string,$depth+2).'<div class="dd-handle">'.$value['content'].' for id #'.$value['id'].'</div>'."'n";
        if (is_array($value['children'])) {
           print_menu_1 ($value['children'],$this_key,$depth+1);
        }
        echo str_repeat($indent_string,$depth+1).'</li>'."'n";
    }
    echo str_repeat($indent_string,$depth).'</ol>'."'n";
}
print_menu_1 ($menu, 0, 0);

请注意,在这种情况下,换行符和$indent_string仅用于使HTML代码看起来更好。