I am getting an array from an API that varies in number of levels but follows the same basic structure – here is a truncated sample as this particular repsonse is 25K lines:
{ "Rows": { "Row": [ { "Header": { "ColData": [ { "value": "Ordinary Income/Expenses" }, { "value": "" } ] }, "Rows": { "Row": [ { "Rows": {}, "Summary": { "ColData": [ { "value": "Gross Profit" }, { "value": "" } ] }, "type": "Section" }, { "Header": { "ColData": [ { "value": "Income" }, { "value": "" } ] }, "Rows": { "Row": [ { "Header": { "ColData": [ { "value": "40000 Sales Income", "id": "31" }, { "value": "" } ] }, "Rows": { "Row": [ { "Rows": { "Row": [ { "ColData": [ { "value": "2022-01-24" }, { "value": "Invoice", "id": "148774" }, { "value": "208232" }, { "value": "Hyatt:#211102", "id": "7568" }, { "value": "JN", "id": "4100000000000368107" }, { "value": "CAPTIVE AIRE" }, { "value": "11000 Accounts Receivable", "id": "80" }, { "value": "38748.00" }, { "value": "38748.00" } ], "type": "Data" },
I need to traverse the json, and where there is data in both [Header][ColData][value] AND [Header][ColData][id] extract the value, id (in this snippet “value”: “40000 Sales Income”, “id”: “31”) and the data that immediately follows the “value”/”id” in [Rows][Row][Rows][Row][ColData] (in this snippet starting with “ColData”: [{“value”: “2022-01-24″…)
[Rows][Row][Rows][Row][ColData] will have one to a few hundred subarrays. I can extract the data from the subarrays once they are found – it’s just managing the varying depths of the array that is warping my brain.
[Rows][Row][Rows][Summary] can be discarded as well.
I have tried multiple foreach loops – but by time I get 5 or 6 levels deep it gets very confusing. The number of Header sections varies depending on the report type. The [Rows][Row] nesting is multiple layers deep… I’m sure there has to be a better way than nesting foreach loops…
Advertisement
Answer
This is what I’ve come up with. Kindly modify it to meet your need.
$array = json_decode($json, true); function traverse_some_array($array){ $result = []; foreach($array['Rows']['Row'] ?? [] as $row){ if( !empty($row['Header']['ColData']) ){ foreach($row['Header']['ColData'] as $coldata){ if( isset($coldata['value'], $coldata['id']) ){ // there is data in both [Header][ColData][value] AND [Header][ColData][id] // extract the value, id (in this snippet "value": "40000 Sales Income", "id": "31") $extract_data = [ 'value' => $coldata['value'], 'id' => $coldata['id'] ]; // the data that immediately follows the "value"/"id" in [Rows][Row][Rows][Row][ColData] $immediate_coldata = $row['Rows']['Row'] ?? []; // you can do what ever you want with the results, eg return it or push it to a result array $result[] = [ 'extract_data' => $extract_data, 'immediate_coldata' => $immediate_coldata ]; }else{ // continue traversing the array $result = array_merge($result, traverse_some_array($row)); } } } } return $result; } print_r(traverse_some_array($array));