PHP 递归 JSON 子项搜索

Posted

技术标签:

【中文标题】PHP 递归 JSON 子项搜索【英文标题】:PHP Recursive JSON Children Search 【发布时间】:2017-05-10 05:08:39 【问题描述】:

我需要解析如下所示的 JSON:


    "mdfId":"282088127",
    "mdfConcept":"ME 3400EG-12CS-M Switch",
    "children":[
        
            "mdfId":"007",
            "mdfConcept":"Another item",
            "children": [
                // many more here
            ]
        ,
        
             "mdfId":"008",
             "mdfConcept":"Another one",
             "children": [
                 
                     "mdfId":"010",
                     "mdfConcept":"What I'm looking for!",
                     "children": [] // no children
                 
             ]
        ,
        // many more here
    ]
,

这是一个递归结构,其中每个元素都有mdfIdmdfConceptchildren 键。

假设我需要在这个结构中找到带有ID=010 的节点。我不知道它位于哪个级别(例如,它可以位于顶层,也可以位于下面的几个 children 节点)。

我目前的做法是:

$mdfId = '010'; // what I'm loking for

foreach ($jsonResponse as $category) 
    while (true) 
        if ($category['mdfId'] == $mdfId) 
            // we found it!
            $categoryDevices[$mdfId] = $category['children'];
            break 2;
        

        if (!empty($category['children'])) 
            next_cat:

            if (is_null($category['children'])) 
                break;
            

            $category = array_shift($category['children']);
            continue;
        

        if (empty($category['children'])) 
            goto next_cat;
        
    

但目前的方法会遗漏一些情况。如何优化这个递归循环,以便它检查同一级别的所有节点,并且每个节点都可以通过任意数量的 children 键访问?

【问题讨论】:

【参考方案1】:

您的 JSON 对象的一个​​令人尴尬的特性是,虽然每个 children 成员都是“子”结构的数组,顶层是对象本身,所以这是一个障碍真正的递归方法。

我们可以通过将源 JSON 对象转换为与嵌套级别相同的结构来解决问题,即:

$jsonResponse 作为原始对象 改用['children' => $jsonResponse]

这样,它应该可以使用这样的东西:

$mdfId = '010'; // what I'm loking for

if ($result = look4id(['children' => $jsonResponse], $mdfId) 
    $categoryDevices[$mdfId] = $result;


function look4id($source, $id) 
    foreach ($source as $child) 
        if ($child['mdfId'] == $id) 
            return $source['children'];
         else 
            if ($source['children']) 
                return look4id($source['children'], $id);
            
        
    

【讨论】:

总体上很好的答案和方法。允许我将发现率从 30% 提高到 60%。但是,一旦循环进入多个children 深度,它就会忘记更高级别上未触及的元素。因此,如果007008 以相反的顺序放置,脚本将检查008 及其子010,但完全错过了007 @DenisBobrovnikov 哼...有趣的问题!您能否发布一个 JSON 对象的示例,如果不是太重,找不到哪个键? (您可以编辑您的 OP 并将对象放入 SO sn-p)【参考方案2】:

所以基本上我编写了一个不返回任何内容的函数,而是从参数中填充了一个变量。

function findRecursiveArrayNodeById($id, $array, &$node) 
    foreach ($array as $child) 
        if (isset($child['mdfId']) && $child['mdfId'] == $id) 
            $node = $child;
            return;
        

        if (!empty($child['children'])) 
            findRecursiveArrayNodeById($id, $child['children'], $node);
        
    

用法如下:

$result = false;

findRecursiveArrayNodeById($mdfId, $category_json, $result);

if (!$result) 
    println("did not find $mdfId");
    continue;

【讨论】:

以上是关于PHP 递归 JSON 子项搜索的主要内容,如果未能解决你的问题,请参考以下文章

递归 JSON 模式

JSON对象中的JavaScript递归搜索

text 递归搜索JSON数组 - 按键获取值

php 递归数组搜索

PHP 递归数组密钥搜索

使用 PHP 递归搜索目录中的文件并更改值