1

I need to parse JSON which looks like this:

{
    "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
    ]
},

This is a recursive structure in which every element has mdfId, mdfConcept and children keys.

Say I need to find node with ID=010 within this structure. I don't know at which level it lies (e.g. it can be on top level, or several children nodes below).

My current approach is:

$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;
        }
    }
}

But current approach misses some cases. How can I optimize this recursive loop so it checks all nodes on same level and each one accesible through any number of children keys?

2 Answers 2

2

An embarrassing feature of your JSON object is that, while each children member is an array of the "child" structure, the top level one is the object itself, so it's an obstacle to a really recursive approach.

We might workaround by turning the source JSON object into the same structure as nested levels, i.e.:

  • having $jsonResponse as original object
  • use ['children' => $jsonResponse] instead

This way, it should work with something like this:

$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);
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Overall good answer and approach. Allowed me to increase findings rate from 30% to 60%. However once the loop goes into several children deep, it forgets about untouched elements on higher levels. So if 007 and 008 were placed in reverse order, script would have checked 008 and its child 010 but totally missed 007.
@DenisBobrovnikov Hum... interesting issue! Could you post an example of a JSON object and which key is not found, if not too heavy? (you might edit your OP and put the object in a SO snippet)
1

So basically I wrote a function that didn't return anything, but rather populated a variable from arguments.

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);
        }
    }
}

Usage as follows:

$result = false;

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

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.