2016-12-25 8 views
0

Мне нужно разобрать JSON, который выглядит следующим образом:PHP Рекурсивного 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 
    ] 
}, 

Это рекурсивная структура, в которой каждый элемент имеет mdfId, mdfConcept и children ключей.

Скажите, что мне нужно найти узел с 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?

ответ

0

Так что в основном я написал функцию, которая ничего не возвращала, а заполняла переменную из аргументов.

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

В целом хороший ответ и подход. Позвольте мне увеличить частоту выписки с 30% до 60%. Однако, как только цикл переходит в несколько «детей», он забывает о нетронутых элементах на более высоких уровнях. Поэтому, если '007' и' 008' были помещены в обратном порядке, скрипт проверил бы '008' и его дочерний' 010', но полностью пропустил '007'. –

+0

@DenisBobrovnikov Hum ... интересный выпуск! Не могли бы вы разместить пример объекта JSON и какой ключ не найти, если он не слишком тяжелый? (вы можете отредактировать свой OP и поместить объект в фрагмент SO) – cFreed

Смежные вопросы