Scubadiver Scubadiver - 7 months ago 62
PHP Question

Parsing nested array of unknown depth

I am getting json files from a third party with variable depths of key:value pairs similar to this:
*** Edited JSON to clarify tablenames which will be used in mysql db. KEY's are columns in the tables, Values are data. The column names will be static from json to json.

{
"Key1": "Value1", //non-nested key:value go to default table
"Key2": "Value2",
"Key3": "Value3",
"Table1": [],
"Table2": [{
"Key1": "Value1",
"Key2": "Value2",
"Key3": "Value3"},

{"Key1": "Value1",
"Key2": "Value2",
"Key3": "Value3"}],

"Table3": [
{"Key1": "Value1",
"Key2": "Value2",
"Key3": "Value3"},
{"Table4": [
{"Key1": "Value1",
"Key2": "Value2",
"Key3": "Value3"},
{"Table5": [
{"Key1": "Value1",
"Key2": "Value2",
"Key3": "Value3"}]
}]
}]
}


** This example passes JSON validation

For the intial Key:Value pairs (not in a nested array) I need to set a tablename, insert all the non-nested values into the table. For the nested Key:Value pairs, the tablename needs to be set to the Array key, i.e. Array1, Array2, Array3, etc. where the nested Key is the column name and Value is the data.

I have been trying to reiterate the array using RecursiveIteratorIterator (I understand there are some speed advantages to this over nested foreach processing of the array) but either way.. I'm having trouble separating the nested arrays and pulling out the underlying Key:Value.

I'm trying this:

$iterator = new RecursiveIteratorIterator(
new RecursiveArrayIterator($data1),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($iterator as $key=>$value){
if (!is_array($value)){
//echo $key." KEY is not an array <br>";
}

if(is_array($value)){
//echo $key." KEY is an array <br>";
foreach($value as $key1=>$val1){
if (is_array($val1)){
//echo $key1."KEY 1 is an array<br>";
}
}
}
}





UPDATE

User @olibiaz proposed a solution that is almost 100% correct:

function toto(array $input, $tableName = '')
{
foreach ($input as $key => $element) {
if (is_array($element)) {
toto($element, $key);
} else {
if ($tableName === '') {
// here is the non nested elelement,
// you can choose the tableName you want
$tableName = 'NonNestedTableName';
}
// place your insert here or whatever you want
// here, the tablename is the index of the nested array
echo "TableName: $tableName, Key: $key, Data: $element \n";
}
}
}


Here is the output I get when running the above code on my JSON data:

TableName: project, Key: Key1, Data: Value1 // "project" used for non-nested
TableName: project, Key: Key2, Data: Value2
TableName: project, Key: Key3, Data: Value3
TableName: 0, Key: Key1, Data: Value1 // Tablename needs to be "Array2"
TableName: 0, Key: Key2, Data: Value2 // for these 3 data sets
TableName: 0, Key: Key3, Data: Value3
TableName: 1, Key: Key1, Data: Value1 // Tablename needs to be "Array2"
TableName: 1, Key: Key2, Data: Value2
TableName: 1, Key: Key3, Data: Value3
TableName: 0, Key: Key1, Data: Value1 // Tablename needs to be "Array3"
TableName: 0, Key: Key2, Data: Value2
TableName: 0, Key: Key3, Data: Value3
TableName: 0, Key: Key1, Data: Value1 // Tablename needs to be "Array4"
TableName: 0, Key: Key2, Data: Value2
TableName: 0, Key: Key3, Data: Value3
TableName: 0, Key: Key1, Data: Value1 // Tablename needs to be "Array5"
TableName: 0, Key: Key2, Data: Value2
TableName: 0, Key: Key3, Data: Value3


However, instead of using the numerical index for table name, I need to use the Key name for the array. Perhaps olibiaz or another user has a suggestion as to how this can be achieved?

Answer

EDIT after all the comments and exchanges. I'll take your example to be more precise

<?php

$inputJson = '{                         
   "Key1": "Value1",                      
   "Key2": "Value2",                      
   "Key3": "Value3",                                 
   "Table1": [],                      
   "Table2": [{                      
      "Key1": "Value1",                  
      "Key2": "Value2",                  
      "Key3": "Value3"},
     {
        "Key1": "Value1",                  
        "Key2": "Value2",                  
        "Key3": "Value3"}],
   "Table3": [{
        "Key1": "Value1",                  
        "Key2": "Value2",                  
        "Key3": "Value3"},
         {
           "Table4": [{
              "Key1": "Value1",              
              "Key2": "Value2",              
              "Key3": "Value3"},
           {
              "Table5": [{
                 "Key1": "Value1",          
                 "Key2": "Value2",          
                 "Key3": "Value3"}]
             }]
       }]    
 }';

So The input is the same as you, then here is the recursive function

function toto(array $input, $tableName = '')
{
    foreach ($input as $key => $element) {
        if (is_array($element)) {
            // if key is integer its the first level of array so we keep the $tablename - edited part
            $key = is_int($key) ? $tableName : $key;
            toto($element, $key);
        } else {
            if ($tableName === '') {
                $tableName = 'NonNestedTableName';
            }
            echo "TableName: $tableName, Key: $key, Data: $element \n";
        }
    }
}

$inputArray = json_decode($inputJson, true);

toto($inputArray);

This will display

TableName: NonNestedTableName, Key: Key1, Data: Value1

TableName: NonNestedTableName, Key: Key2, Data: Value2

TableName: NonNestedTableName, Key: Key3, Data: Value3

TableName: Table2, Key: Key1, Data: Value1

TableName: Table2, Key: Key2, Data: Value2

TableName: Table2, Key: Key3, Data: Value3

TableName: Table2, Key: Key1, Data: Value1

TableName: Table2, Key: Key2, Data: Value2

TableName: Table2, Key: Key3, Data: Value3

TableName: Table3, Key: Key1, Data: Value1

TableName: Table3, Key: Key2, Data: Value2

TableName: Table3, Key: Key3, Data: Value3

TableName: Table4, Key: Key1, Data: Value1

TableName: Table4, Key: Key2, Data: Value2

TableName: Table4, Key: Key3, Data: Value3

TableName: Table5, Key: Key1, Data: Value1

TableName: Table5, Key: Key2, Data: Value2

TableName: Table5, Key: Key3, Data: Value3